rendered paste body/*************************************************************************** * sslscan - A SSL cipher scanning tool * * Copyright 2007-2009 by Ian Ventura-Whiting (Fizz) * * fizz@titania.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see <http://www.gnu.org/licenses/>. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/// Includes...#include <string.h>#if defined(WIN32)#include <stdio.h>#include <winsock2.h>#include <windows.h>#include <ws2tcpip.h>DWORD dwError;#else#include <netdb.h>#include <unistd.h>#include <sys/socket.h>#endif#include <sys/stat.h>#include <openssl/err.h>#include <openssl/ssl.h>#include <openssl/pkcs12.h>#include <openssl/x509.h>#include <openssl/x509v3.h>#include <openssl/applink.c>// Defines...#define false 0#define true 1#define mode_help 0#define mode_version 1#define mode_single 2#define mode_multiple 3#define BUFFERSIZE 1024#define ssl_all 0#define ssl_v2 1#define ssl_v3 2#define tls_v1 3// Colour Console Output...#if !defined(WIN32)const char *RESET = "[0m"; // DEFAULTconst char *COL_RED = "[31m"; // REDconst char *COL_BLUE = "[34m"; // BLUEconst char *COL_GREEN = "[32m"; // GREEN#elseconst char *RESET = "";const char *COL_RED = "";const char *COL_BLUE = "";const char *COL_GREEN = "";#endifconst char *program_banner = " _\n" " ___ ___| |___ ___ __ _ _ __\n" " / __/ __| / __|/ __/ _` | '_ \\\n" " \\__ \\__ \\ \\__ \\ (_| (_| | | | |\n" " |___/___/_|___/\\___\\__,_|_| |_|\n\n" " Version 1.8.2\n" " http://www.titania.co.uk\n" " Copyright Ian Ventura-Whiting 2009\n";const char *program_version = "sslscan version 1.8.2\nhttp://www.titania.co.uk\nCopyright (C) Ian Ventura-Whiting 2009\n";const char *xml_version = "1.8.2";struct sslCipher{ // Cipher Properties... const char *name; char *version; int bits; char description[512]; SSL_METHOD *sslMethod; struct sslCipher *next;};struct sslCheckOptions{ // Program Options... char host[512]; int port; int noFailed; int starttls; int sslVersion; int targets; int pout; int sslbugs; int http; // File Handles... FILE *xmlOutput; // TCP Connection Variables... struct hostent *hostStruct; struct sockaddr_in serverAddress; // SSL Variables... SSL_CTX *ctx; struct sslCipher *ciphers; char *clientCertsFile; char *privateKeyFile; char *privateKeyPassword;};void set_blocking(SSL * ssl){#if defined (WIN32) int fd, res; u_long iMode = 0; if( (fd = SSL_get_rfd(ssl)) ) { res = ioctlsocket(fd, FIONBIO, &iMode); if( res ) { // Something went wrong... dwError = WSAGetLastError(); if (dwError != 0) { printf("%sERROR in set_blocking(): %ld.%s\n", COL_RED, dwError, RESET); } } }#else int fd, flags; /* SSL_get_rfd returns -1 on error */ if( (fd = SSL_get_rfd(ssl)) ) { flags = fcntl(fd, F_GETFL); flags &= ~O_NONBLOCK; fcntl(fd, F_SETFL, flags); } /* SSL_get_wfd returns -1 on error */ if( (fd = SSL_get_wfd(ssl)) ) { flags = fcntl(fd, F_GETFL); flags &= ~O_NONBLOCK; fcntl(fd, F_SETFL, flags); }#endif}// Adds Ciphers to the Cipher List structureint populateCipherList(struct sslCheckOptions *options, SSL_METHOD *sslMethod){ // Variables... int returnCode = true; struct sslCipher *sslCipherPointer; int tempInt; int loop; STACK_OF(SSL_CIPHER) *cipherList; SSL *ssl = NULL; // Setup Context Object... options->ctx = SSL_CTX_new(sslMethod); if (options->ctx != NULL) { SSL_CTX_set_cipher_list(options->ctx, "ALL:COMPLEMENTOFALL"); // Create new SSL object ssl = SSL_new(options->ctx); if (ssl != NULL) { // Get List of Ciphers cipherList = SSL_get_ciphers(ssl); // Create Cipher Struct Entries... for (loop = 0; loop < sk_SSL_CIPHER_num(cipherList); loop++) { // Create Structure... if (options->ciphers == 0) { options->ciphers = malloc(sizeof(struct sslCipher)); sslCipherPointer = options->ciphers; } else { sslCipherPointer = options->ciphers; while (sslCipherPointer->next != 0) sslCipherPointer = sslCipherPointer->next; sslCipherPointer->next = malloc(sizeof(struct sslCipher)); sslCipherPointer = sslCipherPointer->next; } // Init memset(sslCipherPointer, 0, sizeof(struct sslCipher)); // Add cipher information... sslCipherPointer->sslMethod = sslMethod; sslCipherPointer->name = SSL_CIPHER_get_name(sk_SSL_CIPHER_value(cipherList, loop)); sslCipherPointer->version = SSL_CIPHER_get_version(sk_SSL_CIPHER_value(cipherList, loop)); SSL_CIPHER_description(sk_SSL_CIPHER_value(cipherList, loop), sslCipherPointer->description, sizeof(sslCipherPointer->description) - 1); sslCipherPointer->bits = SSL_CIPHER_get_bits(sk_SSL_CIPHER_value(cipherList, loop), &tempInt); } // Free SSL object SSL_free(ssl); } else { returnCode = false; printf("%sERROR: Could not create SSL object.%s\n", COL_RED, RESET); } // Free CTX Object SSL_CTX_free(options->ctx); } // Error Creating Context Object else { returnCode = false; printf("%sERROR: Could not create CTX object.%s\n", COL_RED, RESET); } return returnCode;}// File Existsint fileExists(char *fileName){ // Variables... struct stat fileStats; if (stat(fileName, &fileStats) == 0) return true; else return false;}// Read a line from the input...void readLine(FILE *input, char *lineFromFile, int maxSize){ // Variables... int stripPointer; // Read line from file... fgets(lineFromFile, maxSize, input); // Clear the end-of-line stuff... stripPointer = strlen(lineFromFile) -1; while ((lineFromFile[stripPointer] == '\r') || (lineFromFile[stripPointer] == '\n') || (lineFromFile[stripPointer] == ' ')) { lineFromFile[stripPointer] = 0; stripPointer--; }}// Create a TCP socketint tcpConnect(struct sslCheckOptions *options){ // Variables... int socketDescriptor; char buffer[BUFFERSIZE]; struct sockaddr_in localAddress; int status; // Create Socket socketDescriptor = socket(AF_INET, SOCK_STREAM, 0); if(socketDescriptor < 0) { printf("%s ERROR: Could not open a socket.%s\n", COL_RED, RESET); return 0; } // Configure Local Port localAddress.sin_family = AF_INET; localAddress.sin_addr.s_addr = htonl(INADDR_ANY); localAddress.sin_port = htons(0); status = bind(socketDescriptor, (struct sockaddr *) &localAddress, sizeof(localAddress)); if(status < 0) { printf("%s ERROR: Could not bind to port.%s\n", COL_RED, RESET); return 0; } // Connect status = connect(socketDescriptor, (struct sockaddr *) &options->serverAddress, sizeof(options->serverAddress)); if(status < 0) { printf("%s ERROR: Could not open a connection to host %s on port %d.%s\n", COL_RED, options->host, options->port, RESET); return 0; } // If STARTTLS is required... if (options->starttls == true) { memset(buffer, 0, BUFFERSIZE); recv(socketDescriptor, buffer, BUFFERSIZE - 1, 0); if (strncmp(buffer, "220", 3) != 0) {#if defined( WIN32 ) closesocket(socketDescriptor);#else close(socketDescriptor);#endif printf("%s ERROR: The host %s on port %d did not appear to be an SMTP service.%s\n", COL_RED, options->host, options->port, RESET); return 0; } send(socketDescriptor, "EHLO titania.co.uk\r\n", 20, 0); memset(buffer, 0, BUFFERSIZE); recv(socketDescriptor, buffer, BUFFERSIZE - 1, 0); if (strncmp(buffer, "250", 3) != 0) {#if defined (WIN32) closesocket(socketDescriptor);#else close(socketDescriptor);#endif printf("%s ERROR: The SMTP service on %s port %d did not respond with status 250 to our HELO.%s\n", COL_RED, options->host, options->port, RESET); return 0; } send(socketDescriptor, "STARTTLS\r\n", 10, 0); memset(buffer, 0, BUFFERSIZE); recv(socketDescriptor, buffer, BUFFERSIZE - 1, 0); if (strncmp(buffer, "220", 3) != 0) {#if defined (WIN32) closesocket(socketDescriptor);#else close(socketDescriptor);#endif printf("%s ERROR: The SMTP service on %s port %d did not appear to support STARTTLS.%s\n", COL_RED, options->host, options->port, RESET); return 0; } } // Return return socketDescriptor;}// Private Key Password Callback...static int password_callback(char *buf, int size, int rwflag, void *userdata){ strncpy(buf, (char *)userdata, size); buf[strlen(userdata)] = 0; return strlen(userdata);}// Load client certificates/private keys...int loadCerts(struct sslCheckOptions *options){ // Variables... int status = 1; PKCS12 *pk12 = NULL; FILE *pk12File = NULL; X509 *cert = NULL; EVP_PKEY *pkey = NULL; STACK_OF(X509) *ca = NULL; // Configure PKey password... if (options->privateKeyPassword != 0) { SSL_CTX_set_default_passwd_cb_userdata(options->ctx, (void *)options->privateKeyPassword); SSL_CTX_set_default_passwd_cb(options->ctx, password_callback); } // Seperate Certs and PKey Files... if ((options->clientCertsFile != 0) && (options->privateKeyFile != 0)) { // Load Cert... if (!SSL_CTX_use_certificate_file(options->ctx, options->clientCertsFile, SSL_FILETYPE_PEM)) { if (!SSL_CTX_use_certificate_file(options->ctx, options->clientCertsFile, SSL_FILETYPE_ASN1)) { if (!SSL_CTX_use_certificate_chain_file(options->ctx, options->clientCertsFile)) { printf("%s Could not configure certificate(s).%s\n", COL_RED, RESET); status = 0; } } } // Load PKey... if (status != 0) { if (!SSL_CTX_use_PrivateKey_file(options->ctx, options->privateKeyFile, SSL_FILETYPE_PEM)) { if (!SSL_CTX_use_PrivateKey_file(options->ctx, options->privateKeyFile, SSL_FILETYPE_ASN1)) { if (!SSL_CTX_use_RSAPrivateKey_file(options->ctx, options->privateKeyFile, SSL_FILETYPE_PEM)) { if (!SSL_CTX_use_RSAPrivateKey_file(options->ctx, options->privateKeyFile, SSL_FILETYPE_ASN1)) { printf("%s Could not configure private key.%s\n", COL_RED, RESET); status = 0; } } } } } } // PKCS Cert and PKey File... else if (options->privateKeyFile != 0) { pk12File = fopen(options->privateKeyFile, "rb"); if (pk12File != NULL) { pk12 = d2i_PKCS12_fp(pk12File, NULL); if (!pk12) { status = 0; printf("%s Could not read PKCS#12 file.%s\n", COL_RED, RESET); } else { if (!PKCS12_parse(pk12, options->privateKeyPassword, &pkey, &cert, &ca)) { status = 0; printf("%s Error parsing PKCS#12. Are you sure that password was correct?%s\n", COL_RED, RESET); } else { if (!SSL_CTX_use_certificate(options->ctx, cert)) { status = 0; printf("%s Could not configure certificate.%s\n", COL_RED, RESET); } if (!SSL_CTX_use_PrivateKey(options->ctx, pkey)) { status = 0; printf("%s Could not configure private key.%s\n", COL_RED, RESET); } } PKCS12_free(pk12); } fclose(pk12File); } else { printf("%s Could not open PKCS#12 file.%s\n", COL_RED, RESET); status = 0; } } // Check Cert/Key... if (status != 0) { if (!SSL_CTX_check_private_key(options->ctx)) { printf("%s Prvate key does not match certificate.%s\n", COL_RED, RESET); return false; } else return true; } else return false;}// Test a cipher...int testCipher(struct sslCheckOptions *options, struct sslCipher *sslCipherPointer){ // Variables... int cipherStatus; int status = true; int socketDescriptor = 0; SSL *ssl = NULL; BIO *cipherConnectionBio; BIO *stdoutBIO = NULL; char requestBuffer[200]; char buffer[50]; int resultSize = 0; // Create request buffer... memset(requestBuffer, 0, 200);#if defined (WIN32) _snprintf(requestBuffer, 199, "GET / HTTP/1.0\r\nUser-Agent: SSLScan\r\nHost: %s\r\n\r\n", options->host);#else snprintf(requestBuffer, 199, "GET / HTTP/1.0\r\nUser-Agent: SSLScan\r\nHost: %s\r\n\r\n", options->host);#endif // Connect to host socketDescriptor = tcpConnect(options); if (socketDescriptor != 0) { if (SSL_CTX_set_cipher_list(options->ctx, sslCipherPointer->name) != 0) { // Create SSL object... ssl = SSL_new(options->ctx); if (ssl != NULL) { // Connect socket and BIO cipherConnectionBio = BIO_new_socket(socketDescriptor, BIO_NOCLOSE); // Connect SSL and BIO SSL_set_bio(ssl, cipherConnectionBio, cipherConnectionBio); // Connect SSL over socket cipherStatus = SSL_connect(ssl); // Show Cipher Status if (!((options->noFailed == true) && (cipherStatus != 1))) { if (options->xmlOutput != 0) fprintf(options->xmlOutput, " <cipher status=\""); if (cipherStatus == 1) { if (options->xmlOutput != 0) fprintf(options->xmlOutput, "accepted\""); if (options->pout == true) printf("|| Accepted || "); else printf(" Accepted "); if (options->http == true) { // Stdout BIO... stdoutBIO = BIO_new(BIO_s_file()); BIO_set_fp(stdoutBIO, stdout, BIO_NOCLOSE); // HTTP Get... SSL_write(ssl, requestBuffer, sizeof(requestBuffer)); memset(buffer ,0 , 50); resultSize = SSL_read(ssl, buffer, 49); if (resultSize > 9) { int loop = 0; for (loop = 9; (loop < 49) && (buffer[loop] != 0) && (buffer[loop] != '\r') && (buffer[loop] != '\n'); loop++) { } buffer[loop] = 0; // Output HTTP code... if (options->pout == true) printf("%s || ", buffer + 9); else { printf("%s", buffer + 9); loop = strlen(buffer + 9); while (loop < 17) { loop++; printf(" "); } } if (options->xmlOutput != 0) fprintf(options->xmlOutput, " http=\"%s\"", buffer + 9); } else { // Output HTTP code... if (options->pout == true) printf("|| || "); else printf(" "); } } } else if (cipherStatus == 0) { if (options->xmlOutput != 0) fprintf(options->xmlOutput, "rejected\""); if (options->http == true) { if (options->pout == true) printf("|| Rejected || N/A || "); else printf(" Rejected N/A "); } else { if (options->pout == true) printf("|| Rejected || "); else printf(" Rejected "); } } else { if (options->xmlOutput != 0) fprintf(options->xmlOutput, "failed\""); if (options->http == true) { if (options->pout == true) printf("|| Failed || N/A || "); else printf(" Failed N/A "); } else { if (options->pout == true) printf("|| Failed || "); else printf(" Failed "); } } if (options->xmlOutput != 0) fprintf(options->xmlOutput, " sslversion=\""); if (sslCipherPointer->sslMethod == SSLv2_client_method()) { if (options->xmlOutput != 0) fprintf(options->xmlOutput, "SSLv2\" bits=\""); if (options->pout == true) printf("SSLv2 || "); else printf("SSLv2 "); } else if (sslCipherPointer->sslMethod == SSLv3_client_method()) { if (options->xmlOutput != 0) fprintf(options->xmlOutput, "SSLv3\" bits=\""); if (options->pout == true) printf("SSLv3 || "); else printf("SSLv3 "); } else { if (options->xmlOutput != 0) fprintf(options->xmlOutput, "TLSv1\" bits=\""); if (options->pout == true) printf("TLSv1 || "); else printf("TLSv1 "); } if (options->pout == true) printf("%d || ", sslCipherPointer->bits); else printf("%3d bits ", sslCipherPointer->bits); if (options->xmlOutput != 0) fprintf(options->xmlOutput, "%d\" cipher=\"%s\" />\n", sslCipherPointer->bits, sslCipherPointer->name); if (options->pout == true) printf("%s ||\n", sslCipherPointer->name); else printf("%s\n", sslCipherPointer->name); } // Disconnect SSL over socket if (cipherStatus == 1) SSL_shutdown(ssl); // Free SSL object SSL_free(ssl); } else { status = false; printf("%s ERROR: Could create SSL object.%s\n", COL_RED, RESET); } } else { status = false; printf("%s ERROR: Could set cipher %s.%s\n", COL_RED, sslCipherPointer->name, RESET); } // Disconnect from host#if defined (WIN32) closesocket(socketDescriptor);#else close(socketDescriptor);#endif } // Could not connect else status = false; return status;}// Check if the server supports renegotiationint testRenegotiation(struct sslCheckOptions *options, SSL_METHOD *sslMethod){ // Variables... int cipherStatus; int status = true; int socketDescriptor = 0; SSL *ssl = NULL; BIO *cipherConnectionBio;// int tempInt2; // Connect to host socketDescriptor = tcpConnect(options); if (socketDescriptor != 0) { // Setup Context Object... options->ctx = SSL_CTX_new(sslMethod); if (options->ctx != NULL) { if (SSL_CTX_set_cipher_list(options->ctx, "ALL:COMPLEMENTOFALL") != 0) { // Load Certs if required... if ((options->clientCertsFile != 0) || (options->privateKeyFile != 0)) status = loadCerts(options); if (status == true) { // Create SSL object... ssl = SSL_new(options->ctx); if (ssl != NULL) { // Connect socket and BIO cipherConnectionBio = BIO_new_socket(socketDescriptor, BIO_NOCLOSE); // Connect SSL and BIO SSL_set_bio(ssl, cipherConnectionBio, cipherConnectionBio); // Connect SSL over socket cipherStatus = SSL_connect(ssl); if (cipherStatus == 1) { /* assume ssl is connected and error free up to here */ set_blocking(ssl); /* this is unnecessary if it is already blocking */ SSL_renegotiate(ssl); // Ask to renegotiate the connection SSL_do_handshake(ssl); // Send renegotiation request to server if (ssl->state == SSL_ST_OK) { //ssl->state |= SSL_ST_ACCEPT; //ssl->state = SSL_ST_ACCEPT; int res = SSL_do_handshake(ssl); // Send renegotiation request to server if( res != 1 ) { printf("\n\nSSL_do_handshake() call failed\n"); } if (ssl->state == SSL_ST_OK) { /* our renegotiation is complete */ status = true; printf("\n\n%sRenegotiation request succeeded%s\n", COL_RED, RESET); } else { status = false; printf("\n\n%sFailed to complete renegotiation %s\n", COL_RED, RESET); } } else { status = false; printf("\n\n%sFailed to send renegotiation request%s\n", COL_RED, RESET); } // Disconnect SSL over socket SSL_shutdown(ssl); } // Free SSL object SSL_free(ssl); } else { status = false; printf("%s ERROR: Could create SSL object.%s\n", COL_RED, RESET); } } } else { status = false; printf("%s ERROR: Could set cipher.%s\n", COL_RED, RESET); } // Free CTX Object SSL_CTX_free(options->ctx); } // Error Creating Context Object else { status = false; printf("%sERROR: Could not create CTX object.%s\n", COL_RED, RESET); } // Disconnect from host#if defined (WIN32) closesocket(socketDescriptor);#else close(socketDescriptor);#endif } // Could not connect else status = false; if (options->xmlOutput != 0) fprintf(options->xmlOutput, " <renegotiation supported=\"%d\" />\n", status); return status; }// Test for prefered ciphersint defaultCipher(struct sslCheckOptions *options, SSL_METHOD *sslMethod){ // Variables... int cipherStatus; int status = true; int socketDescriptor = 0; SSL *ssl = NULL; BIO *cipherConnectionBio; int tempInt2; // Connect to host socketDescriptor = tcpConnect(options); if (socketDescriptor != 0) { // Setup Context Object... options->ctx = SSL_CTX_new(sslMethod); if (options->ctx != NULL) { if (SSL_CTX_set_cipher_list(options->ctx, "ALL:COMPLEMENTOFALL") != 0) { // Load Certs if required... if ((options->clientCertsFile != 0) || (options->privateKeyFile != 0)) status = loadCerts(options); if (status == true) { // Create SSL object... ssl = SSL_new(options->ctx); if (ssl != NULL) { // Connect socket and BIO cipherConnectionBio = BIO_new_socket(socketDescriptor, BIO_NOCLOSE); // Connect SSL and BIO SSL_set_bio(ssl, cipherConnectionBio, cipherConnectionBio); // Connect SSL over socket cipherStatus = SSL_connect(ssl); if (cipherStatus == 1) { if (sslMethod == SSLv2_client_method()) { if (options->xmlOutput != 0) fprintf(options->xmlOutput, " <defaultcipher sslversion=\"SSLv2\" bits=\""); if (options->pout == true) printf("|| SSLv2 || "); else printf(" SSLv2 "); } else if (sslMethod == SSLv3_client_method()) { if (options->xmlOutput != 0) fprintf(options->xmlOutput, " <defaultcipher sslversion=\"SSLv3\" bits=\""); if (options->pout == true) printf("|| SSLv3 || "); else printf(" SSLv3 "); } else { if (options->xmlOutput != 0) fprintf(options->xmlOutput, " <defaultcipher sslversion=\"TLSv1\" bits=\""); if (options->pout == true) printf("|| TLSv1 || "); else printf(" TLSv1 "); } if (options->pout == true) printf("%d bits || ", SSL_get_cipher_bits(ssl, &tempInt2)); else printf("%3d bits ", SSL_get_cipher_bits(ssl, &tempInt2)); if (options->xmlOutput != 0) fprintf(options->xmlOutput, "%d\" cipher=\"%s\" />\n", SSL_get_cipher_bits(ssl, &tempInt2), SSL_get_cipher_name(ssl)); if (options->pout == true) printf("%s ||\n", SSL_get_cipher_name(ssl)); else printf("%s\n", SSL_get_cipher_name(ssl)); // Disconnect SSL over socket SSL_shutdown(ssl); } // Free SSL object SSL_free(ssl); } else { status = false; printf("%s ERROR: Could create SSL object.%s\n", COL_RED, RESET); } } } else { status = false; printf("%s ERROR: Could set cipher.%s\n", COL_RED, RESET); } // Free CTX Object SSL_CTX_free(options->ctx); } // Error Creating Context Object else { status = false; printf("%sERROR: Could not create CTX object.%s\n", COL_RED, RESET); } // Disconnect from host#if defined (WIN32) closesocket(socketDescriptor);#else close(socketDescriptor);#endif } // Could not connect else status = false; return status;}// Get certificate...int getCertificate(struct sslCheckOptions *options){ // Variables... int cipherStatus = 0; int status = true; int socketDescriptor = 0; SSL *ssl = NULL; BIO *cipherConnectionBio = NULL; BIO *stdoutBIO = NULL; BIO *fileBIO = NULL; X509 *x509Cert = NULL; EVP_PKEY *publicKey = NULL; SSL_METHOD *sslMethod = NULL; ASN1_OBJECT *asn1Object = NULL; X509_EXTENSION *extension = NULL; char buffer[1024]; long tempLong = 0; int tempInt = 0; int tempInt2 = 0; long verifyError = 0; // Connect to host socketDescriptor = tcpConnect(options); if (socketDescriptor != 0) { // Setup Context Object... sslMethod = SSLv23_method(); options->ctx = SSL_CTX_new(sslMethod); if (options->ctx != NULL) { if (SSL_CTX_set_cipher_list(options->ctx, "ALL:COMPLEMENTOFALL") != 0) { // Load Certs if required... if ((options->clientCertsFile != 0) || (options->privateKeyFile != 0)) status = loadCerts(options); if (status == true) { // Create SSL object... ssl = SSL_new(options->ctx); if (ssl != NULL) { // Connect socket and BIO cipherConnectionBio = BIO_new_socket(socketDescriptor, BIO_NOCLOSE); // Connect SSL and BIO SSL_set_bio(ssl, cipherConnectionBio, cipherConnectionBio); // Connect SSL over socket cipherStatus = SSL_connect(ssl); if (cipherStatus == 1) { // Setup BIO's stdoutBIO = BIO_new(BIO_s_file()); BIO_set_fp(stdoutBIO, stdout, BIO_NOCLOSE); if (options->xmlOutput != 0) { fileBIO = BIO_new(BIO_s_file()); BIO_set_fp(fileBIO, options->xmlOutput, BIO_NOCLOSE); } // Get Certificate... printf("\n %sSSL Certificate:%s\n", COL_BLUE, RESET); if (options->xmlOutput != 0) fprintf(options->xmlOutput, " <certificate>\n"); x509Cert = SSL_get_peer_certificate(ssl); if (x509Cert != NULL) { //SSL_set_verify(ssl, SSL_VERIFY_NONE|SSL_VERIFY_CLIENT_ONCE, NULL); // Cert Version if (!(X509_FLAG_COMPAT & X509_FLAG_NO_VERSION)) { tempLong = X509_get_version(x509Cert); printf(" Version: %lu\n", tempLong); if (options->xmlOutput != 0) fprintf(options->xmlOutput, " <version>%lu</version>\n", tempLong); } // Cert Serial No. if (!(X509_FLAG_COMPAT & X509_FLAG_NO_SERIAL)) { tempLong = ASN1_INTEGER_get(X509_get_serialNumber(x509Cert)); if (tempLong < 1) { printf(" Serial Number: -%lu\n", tempLong); if (options->xmlOutput != 0) fprintf(options->xmlOutput, " <serial>-%lu</serial>\n", tempLong); } else { printf(" Serial Number: %lu\n", tempLong); if (options->xmlOutput != 0) fprintf(options->xmlOutput, " <serial>%lu</serial>\n", tempLong); } } // Signature Algo... if (!(X509_FLAG_COMPAT & X509_FLAG_NO_SIGNAME)) { printf(" Signature Algorithm: "); i2a_ASN1_OBJECT(stdoutBIO, x509Cert->cert_info->signature->algorithm); printf("\n"); if (options->xmlOutput != 0) { fprintf(options->xmlOutput, " <signature-algorithm>"); i2a_ASN1_OBJECT(fileBIO, x509Cert->cert_info->signature->algorithm); fprintf(options->xmlOutput, "</signature-algorithm>\n"); } } // SSL Certificate Issuer... if (!(X509_FLAG_COMPAT & X509_FLAG_NO_ISSUER)) { X509_NAME_oneline(X509_get_issuer_name(x509Cert), buffer, sizeof(buffer) - 1); printf(" Issuer: %s\n", buffer); if (options->xmlOutput != 0) fprintf(options->xmlOutput, " <issuer>%s</issuer>\n", buffer); } // Validity... if (!(X509_FLAG_COMPAT & X509_FLAG_NO_VALIDITY)) { printf(" Not valid before: "); ASN1_TIME_print(stdoutBIO, X509_get_notBefore(x509Cert)); if (options->xmlOutput != 0) { fprintf(options->xmlOutput, " <not-valid-before>"); ASN1_TIME_print(fileBIO, X509_get_notBefore(x509Cert)); fprintf(options->xmlOutput, "</not-valid-before>\n"); } printf("\n Not valid after: "); ASN1_TIME_print(stdoutBIO, X509_get_notAfter(x509Cert)); printf("\n"); if (options->xmlOutput != 0) { fprintf(options->xmlOutput, " <not-valid-after>"); ASN1_TIME_print(fileBIO, X509_get_notAfter(x509Cert)); fprintf(options->xmlOutput, "</not-valid-after>\n"); } } // SSL Certificate Subject... if (!(X509_FLAG_COMPAT & X509_FLAG_NO_SUBJECT)) { X509_NAME_oneline(X509_get_subject_name(x509Cert), buffer, sizeof(buffer) - 1); printf(" Subject: %s\n", buffer); if (options->xmlOutput != 0) fprintf(options->xmlOutput, " <subject>%s</subject>\n", buffer); } // Public Key Algo... if (!(X509_FLAG_COMPAT & X509_FLAG_NO_PUBKEY)) { printf(" Public Key Algorithm: "); i2a_ASN1_OBJECT(stdoutBIO, x509Cert->cert_info->key->algor->algorithm); printf("\n"); if (options->xmlOutput != 0) { fprintf(options->xmlOutput, " <pk-algorithm>"); i2a_ASN1_OBJECT(fileBIO, x509Cert->cert_info->key->algor->algorithm); fprintf(options->xmlOutput, "</pk-algorithm>\n"); } // Public Key... publicKey = X509_get_pubkey(x509Cert); if (publicKey == NULL) { printf(" Public Key: Could not load\n"); if (options->xmlOutput != 0) fprintf(options->xmlOutput, " <pk error=\"true\" />\n"); } else { switch (publicKey->type) { case EVP_PKEY_RSA: printf(" RSA Public Key: (%d bit)\n", BN_num_bits(publicKey->pkey.rsa->n)); if (options->xmlOutput != 0) fprintf(options->xmlOutput, " <pk error=\"false\" type=\"RSA\" bits=\"%d\">\n", BN_num_bits(publicKey->pkey.rsa->n)); RSA_print(stdoutBIO, publicKey->pkey.rsa, 6); if (options->xmlOutput != 0) { RSA_print(fileBIO, publicKey->pkey.rsa, 4); fprintf(options->xmlOutput, " </pk>\n"); } break; case EVP_PKEY_DSA: printf(" DSA Public Key:\n"); if (options->xmlOutput != 0) fprintf(options->xmlOutput, " <pk error=\"false\" type=\"DSA\">\n"); DSA_print(stdoutBIO, publicKey->pkey.dsa, 6); if (options->xmlOutput != 0) { DSA_print(fileBIO, publicKey->pkey.dsa, 4); fprintf(options->xmlOutput, " </pk>\n"); } break; case EVP_PKEY_EC: printf(" EC Public Key:\n"); if (options->xmlOutput != 0) fprintf(options->xmlOutput, " <pk error=\"false\" type=\"EC\">\n"); EC_KEY_print(stdoutBIO, publicKey->pkey.ec, 6); if (options->xmlOutput != 0) { EC_KEY_print(fileBIO, publicKey->pkey.ec, 4); fprintf(options->xmlOutput, " </pk>\n"); } break; default: printf(" Public Key: Unknown\n"); if (options->xmlOutput != 0) fprintf(options->xmlOutput, " <pk error=\"true\" type=\"unknown\" />\n"); break; } EVP_PKEY_free(publicKey); } } // X509 v3... if (!(X509_FLAG_COMPAT & X509_FLAG_NO_EXTENSIONS)) { if (sk_X509_EXTENSION_num(x509Cert->cert_info->extensions) > 0) { printf(" X509v3 Extensions:\n"); if (options->xmlOutput != 0) fprintf(options->xmlOutput, " <X509v3-Extensions>\n"); for (tempInt = 0; tempInt < sk_X509_EXTENSION_num(x509Cert->cert_info->extensions); tempInt++) { // Get Extension... extension = sk_X509_EXTENSION_value(x509Cert->cert_info->extensions, tempInt); // Print Extension name... printf(" "); asn1Object = X509_EXTENSION_get_object(extension); i2a_ASN1_OBJECT(stdoutBIO, asn1Object); tempInt2 = X509_EXTENSION_get_critical(extension); BIO_printf(stdoutBIO, ": %s\n", tempInt2 ? "critical" : ""); if (options->xmlOutput != 0) { fprintf(options->xmlOutput, " <extension name=\""); i2a_ASN1_OBJECT(fileBIO, asn1Object); BIO_printf(fileBIO, "\"%s>", tempInt2 ? " level=\"critical\"" : ""); } // Print Extension value... if (!X509V3_EXT_print(stdoutBIO, extension, X509_FLAG_COMPAT, 8)) { printf(" "); M_ASN1_OCTET_STRING_print(stdoutBIO, extension->value); } if (options->xmlOutput != 0) { if (!X509V3_EXT_print(fileBIO, extension, X509_FLAG_COMPAT, 0)) M_ASN1_OCTET_STRING_print(fileBIO, extension->value); fprintf(options->xmlOutput, "</extension>\n"); } printf("\n"); } if (options->xmlOutput != 0) fprintf(options->xmlOutput, " </X509v3-Extensions>\n"); } } // Verify Certificate... printf(" Verify Certificate:\n"); verifyError = SSL_get_verify_result(ssl); if (verifyError == X509_V_OK) printf(" Certificate passed verification\n"); else printf(" %s\n", X509_verify_cert_error_string(verifyError)); // Free X509 Certificate... X509_free(x509Cert); } if (options->xmlOutput != 0) fprintf(options->xmlOutput, " </certificate>\n"); // Free BIO BIO_free(stdoutBIO); if (options->xmlOutput != 0) BIO_free(fileBIO); // Disconnect SSL over socket SSL_shutdown(ssl); } // Free SSL object SSL_free(ssl); } else { status = false; printf("%s ERROR: Could create SSL object.%s\n", COL_RED, RESET); } } } else { status = false; printf("%s ERROR: Could set cipher.%s\n", COL_RED, RESET); } // Free CTX Object SSL_CTX_free(options->ctx); } // Error Creating Context Object else { status = false; printf("%sERROR: Could not create CTX object.%s\n", COL_RED, RESET); } // Disconnect from host#if defined (WIN32) closesocket(socketDescriptor);#else close(socketDescriptor);#endif } // Could not connect else status = false; return status;}// Test a single host and port for ciphers...int testHost(struct sslCheckOptions *options){ // Variables... struct sslCipher *sslCipherPointer; int status = true; // Resolve Host Name#if defined (WIN32) WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 1, 1 ); err = WSAStartup( wVersionRequested, &wsaData );#endif options->hostStruct = gethostbyname(options->host);#if defined (WIN32) dwError = WSAGetLastError(); if (dwError != 0) { if (dwError == WSAHOST_NOT_FOUND) { //printf("Host not found\n"); printf("%sERROR: Could not resolve hostname %s: Host not found.%s\n", COL_RED, options->host, RESET); return false; } else if (dwError == WSANO_DATA) { //printf("No data record found\n"); printf("%sERROR: Could not resolve hostname %s: No data record found.%s\n", COL_RED, options->host, RESET); return false; } else { //printf("Function failed with error: %ld\n", dwError); printf("%sERROR: Could not resolve hostname %s: Error(%ld).%s\n", COL_RED, options->host, dwError, RESET); return false; } }#else if (options->hostStruct == NULL) { printf("%sERROR: Could not resolve hostname %s.%s\n", COL_RED, options->host, RESET); return false; }#endif // Configure Server Address and Port options->serverAddress.sin_family = options->hostStruct->h_addrtype; memcpy((char *) &options->serverAddress.sin_addr.s_addr, options->hostStruct->h_addr_list[0], options->hostStruct->h_length); options->serverAddress.sin_port = htons(options->port); // XML Output... if (options->xmlOutput != 0) fprintf(options->xmlOutput, " <ssltest host=\"%s\" port=\"%d\">\n", options->host, options->port); // Test supported ciphers... printf("\n%sTesting SSL server %s on port %d%s\n\n", COL_GREEN, options->host, options->port, RESET); printf(" %sSupported Server Cipher(s):%s\n", COL_BLUE, RESET); if ((options->http == true) && (options->pout == true)) printf("|| Status || HTTP Code || Version || Bits || Cipher ||\n"); else if (options->pout == true) printf("|| Status || Version || Bits || Cipher ||\n"); sslCipherPointer = options->ciphers; while ((sslCipherPointer != 0) && (status == true)) { // Setup Context Object... options->ctx = SSL_CTX_new(sslCipherPointer->sslMethod); if (options->ctx != NULL) { // SSL implementation bugs/workaround if (options->sslbugs) SSL_CTX_set_options(options->ctx, SSL_OP_ALL | 0); else SSL_CTX_set_options(options->ctx, 0); // Load Certs if required... if ((options->clientCertsFile != 0) || (options->privateKeyFile != 0)) status = loadCerts(options); // Test if (status == true) status = testCipher(options, sslCipherPointer); // Free CTX Object SSL_CTX_free(options->ctx); } // Error Creating Context Object else { status = false; printf("%sERROR: Could not create CTX object.%s\n", COL_RED, RESET); } sslCipherPointer = sslCipherPointer->next; } if (status == true) { // Test prefered ciphers... printf("\n %sPrefered Server Cipher(s):%s\n", COL_BLUE, RESET); if (options->pout == true) printf("|| Version || Bits || Cipher ||\n"); switch (options->sslVersion) { case ssl_all: status = defaultCipher(options, SSLv2_client_method()); if (status != false) status = defaultCipher(options, SSLv3_client_method()); if (status != false) status = defaultCipher(options, TLSv1_client_method()); break; case ssl_v2: status = defaultCipher(options, SSLv2_client_method()); break; case ssl_v3: status = defaultCipher(options, SSLv3_client_method()); break; case tls_v1: status = defaultCipher(options, TLSv1_client_method()); break; } } if (status == true) { status = getCertificate(options); } if (status == true) { status = testRenegotiation(options, SSLv23_client_method()); } // XML Output... if (options->xmlOutput != 0) fprintf(options->xmlOutput, " </ssltest>\n"); // Return status... return status;}int main(int argc, char *argv[]){ // Variables... struct sslCheckOptions options; struct sslCipher *sslCipherPointer; int status; int argLoop; int tempInt; int maxSize; int xmlArg; int mode = mode_help; FILE *targetsFile; char line[1024]; // Init... memset(&options, 0, sizeof(struct sslCheckOptions)); options.port = 443; xmlArg = 0; strcpy(options.host, "127.0.0.1"); options.noFailed = false; options.starttls = false; options.sslVersion = ssl_all; options.pout = false; SSL_library_init(); // Get program parameters for (argLoop = 1; argLoop < argc; argLoop++) { // Help if (strcmp("--help", argv[argLoop]) == 0) mode = mode_help; // targets else if ((strncmp("--targets=", argv[argLoop], 10) == 0) && (strlen(argv[argLoop]) > 10)) { mode = mode_multiple; options.targets = argLoop; } // Show only supported else if (strcmp("--no-failed", argv[argLoop]) == 0) options.noFailed = true; // Version else if (strcmp("--version", argv[argLoop]) == 0) mode = mode_version; // XML Output else if (strncmp("--xml=", argv[argLoop], 6) == 0) xmlArg = argLoop; // P Output else if (strcmp("-p", argv[argLoop]) == 0) options.pout = true; // Client Certificates else if (strncmp("--certs=", argv[argLoop], 8) == 0) options.clientCertsFile = argv[argLoop] +8; // Private Key File else if (strncmp("--pk=", argv[argLoop], 5) == 0) options.privateKeyFile = argv[argLoop] +5; // Private Key Password else if (strncmp("--pkpass=", argv[argLoop], 9) == 0) options.privateKeyPassword = argv[argLoop] +9; // StartTLS... else if (strcmp("--starttls", argv[argLoop]) == 0) { options.sslVersion = tls_v1; options.starttls = true; } // SSL v2 only... else if (strcmp("--ssl2", argv[argLoop]) == 0) options.sslVersion = ssl_v2; // SSL v3 only... else if (strcmp("--ssl3", argv[argLoop]) == 0) options.sslVersion = ssl_v3; // TLS v1 only... else if (strcmp("--tls1", argv[argLoop]) == 0) options.sslVersion = tls_v1; // SSL Bugs... else if (strcmp("--bugs", argv[argLoop]) == 0) options.sslbugs = 1; // SSL HTTP Get... else if (strcmp("--http", argv[argLoop]) == 0) options.http = 1; // Host (maybe port too)... else if (argLoop + 1 == argc) { mode = mode_single; // Get host... tempInt = 0; maxSize = strlen(argv[argLoop]); while ((argv[argLoop][tempInt] != 0) && (argv[argLoop][tempInt] != ':')) tempInt++; argv[argLoop][tempInt] = 0; strncpy(options.host, argv[argLoop], sizeof(options.host) -1); // Get port (if it exists)... tempInt++; if (tempInt < maxSize) options.port = atoi(argv[argLoop] + tempInt); } // Not too sure what the user is doing... else mode = mode_help; } // Open XML file output... if ((xmlArg > 0) && (mode != mode_help)) { options.xmlOutput = fopen(argv[xmlArg] + 6, "w"); if (options.xmlOutput == NULL) { printf("%sERROR: Could not open XML output file %s.%s\n", COL_RED, argv[xmlArg] + 6, RESET); exit(0); } // Output file header... fprintf(options.xmlOutput, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document title=\"SSLScan Results\" version=\"%s\" web=\"http://www.titania.co.uk\">\n", xml_version); } switch (mode) { case mode_version: printf("%s%s%s", COL_BLUE, program_version, RESET); break; case mode_help: // Program version banner... printf("%s%s%s\n", COL_BLUE, program_banner, RESET); printf("SSLScan is a fast SSL port scanner. SSLScan connects to SSL\n"); printf("ports and determines what ciphers are supported, which are\n"); printf("the servers prefered ciphers, which SSL protocols are\n"); printf("supported and returns the SSL certificate. Client\n"); printf("certificates / private key can be configured and output is\n"); printf("to text / XML.\n\n"); printf("%sCommand:%s\n", COL_BLUE, RESET); printf(" %s%s [Options] [host:port | host]%s\n\n", COL_GREEN, argv[0], RESET); printf("%sOptions:%s\n", COL_BLUE, RESET); printf(" %s--targets=<file>%s A file containing a list of hosts to\n", COL_GREEN, RESET); printf(" check. Hosts can be supplied with\n"); printf(" ports (i.e. host:port).\n"); printf(" %s--no-failed%s List only accepted ciphers (default\n", COL_GREEN, RESET); printf(" is to listing all ciphers).\n"); printf(" %s--ssl2%s Only check SSLv2 ciphers.\n", COL_GREEN, RESET); printf(" %s--ssl3%s Only check SSLv3 ciphers.\n", COL_GREEN, RESET); printf(" %s--tls1%s Only check TLSv1 ciphers.\n", COL_GREEN, RESET); printf(" %s--pk=<file>%s A file containing the private key or\n", COL_GREEN, RESET); printf(" a PKCS#12 file containing a private\n"); printf(" key/certificate pair (as produced by\n"); printf(" MSIE and Netscape).\n"); printf(" %s--pkpass=<password>%s The password for the private key or\n", COL_GREEN, RESET); printf(" PKCS#12 file.\n"); printf(" %s--certs=<file>%s A file containing PEM/ASN1 formatted\n", COL_GREEN, RESET); printf(" client certificates.\n"); printf(" %s--starttls%s If a STARTTLS is required to kick an\n", COL_GREEN, RESET); printf(" SMTP service into action.\n"); printf(" %s--http%s Test a HTTP connection.\n", COL_GREEN, RESET); printf(" %s--bugs%s Enable SSL implementation bug work-\n", COL_GREEN, RESET); printf(" arounds.\n"); printf(" %s--xml=<file>%s Output results to an XML file.\n", COL_GREEN, RESET); printf(" %s--version%s Display the program version.\n", COL_GREEN, RESET); printf(" %s--help%s Display the help text you are now\n", COL_GREEN, RESET); printf(" reading.\n"); printf("%sExample:%s\n", COL_BLUE, RESET); printf(" %s%s 127.0.0.1%s\n\n", COL_GREEN, argv[0], RESET); break; // Check a single host/port ciphers... case mode_single: case mode_multiple: printf("%s%s%s", COL_BLUE, program_banner, RESET); SSLeay_add_all_algorithms(); ERR_load_crypto_strings(); // Build a list of ciphers... switch (options.sslVersion) { case ssl_all: populateCipherList(&options, SSLv2_client_method()); populateCipherList(&options, SSLv3_client_method()); populateCipherList(&options, TLSv1_client_method()); break; case ssl_v2: populateCipherList(&options, SSLv2_client_method()); break; case ssl_v3: populateCipherList(&options, SSLv3_client_method()); break; case tls_v1: populateCipherList(&options, TLSv1_client_method()); break; } // Do the testing... if (mode == mode_single) status = testHost(&options); else { if (fileExists(argv[options.targets] + 10) == true) { // Open targets file... targetsFile = fopen(argv[options.targets] + 10, "r"); if (targetsFile == NULL) printf("%sERROR: Could not open targets file %s.%s\n", COL_RED, argv[options.targets] + 10, RESET); else { readLine(targetsFile, line, sizeof(line)); while (feof(targetsFile) == 0) { if (strlen(line) != 0) { // Get host... tempInt = 0; while ((line[tempInt] != 0) && (line[tempInt] != ':')) tempInt++; line[tempInt] = 0; strncpy(options.host, line, sizeof(options.host) -1); // Get port (if it exists)... tempInt++; if (strlen(line + tempInt) > 0) options.port = atoi(line + tempInt); // Test the host... status = testHost(&options); } readLine(targetsFile, line, sizeof(line)); } } } else printf("%sERROR: Targets file %s does not exist.%s\n", COL_RED, argv[options.targets] + 10, RESET); } // Free Structures while (options.ciphers != 0) { sslCipherPointer = options.ciphers->next; free(options.ciphers); options.ciphers = sslCipherPointer; } break; } // Close XML file, if required... if ((xmlArg > 0) && (mode != mode_help)) { fprintf(options.xmlOutput, "</document>\n"); fclose(options.xmlOutput); } return 0;}