From 9049aba76b73fa8aabd5f19b11edf355a9ba0b1b Mon Sep 17 00:00:00 2001 From: Sven Dickert Date: Fri, 28 Jun 2019 15:41:35 +0200 Subject: [PATCH 01/52] * a lot "of dereferencing pointer to incomplete type" errors killed with suitable access functions * session is a pointer now * added TLS1_3_VERSION/TLSv1_3_client_method/TLSv1_3_method * SSL_ST_OK is now TLS_ST_OK * in TLS1_3 SSL_CTX_set_cipher_list is now SSL_CTX_set_ciphersuites * you can't disable ciphers in a cipherstring for TLS1_3 with ":!". You have to remove them. * removed the whole ocsp_reponse-handling with OCSP_RESPONSE_print(arg, rsp, 0), there wasn't a print_xml() anywhere * M_ASN1_OCTET_STRING_print is now ASN1_STRING_print --- Makefile | 7 +- sslscan.c | 471 ++++++++++++++++++++++++------------------------------ sslscan.h | 2 +- 3 files changed, 213 insertions(+), 267 deletions(-) diff --git a/Makefile b/Makefile index 11c51ff..227ea7b 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ MANDIR = $(PREFIX)/share/man MAN1DIR = $(MANDIR)/man1 WARNINGS = -Wall -Wformat=2 -Wformat-security -DEFINES = -DVERSION=\"$(GIT_VERSION)\" +DEFINES = -DVERSION=\"$(GIT_VERSION)\" -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3 # for dynamic linking LIBS = -lssl -lcrypto @@ -49,10 +49,7 @@ CFLAGS += -D_FORTIFY_SOURCE=2 -fstack-protector-all -fPIE # Don't enable some hardening flags on OS X because it uses an old version of Clang ifneq ($(OS), Darwin) ifneq ($(OS), SunOS) -# Cygwin's linker does not support -z option. -ifneq ($(findstring CYGWIN,$(OS)),CYGWIN) - LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -endif + LDFLAGS += -pie -z relro -z now endif endif diff --git a/sslscan.c b/sslscan.c index 1790071..90c9777 100644 --- a/sslscan.c +++ b/sslscan.c @@ -88,6 +88,7 @@ #include #include #include + #include #endif #include #include @@ -133,22 +134,14 @@ static int xml_to_stdout = 0; unsigned long SSL_CIPHER_get_id(const SSL_CIPHER* cipher) { return cipher->id; } #endif -// Helper function to recv from socket until EOF or an error -static ssize_t recvall(int sockfd, void *buf, size_t len, int flags) +const SSL_METHOD *TLSv1_3_client_method(void) { - size_t remaining = len; - char *bufptr = buf; - do - { - ssize_t actual = recv(sockfd, bufptr, remaining, flags); - if (actual <= 0) // premature eof or an error? - { - return actual; - } - bufptr += actual; - remaining -= actual; - } while (remaining != 0); - return (ssize_t) len; + return TLS_client_method(); +} + +const SSL_METHOD *TLSv1_3_method(void) +{ + return TLS_method(); } // Adds Ciphers to the Cipher List structure @@ -236,7 +229,7 @@ int readOrLogAndClose(int fd, void* buffer, size_t len, const struct sslCheckOpt if (len < 2) return 1; - n = recvall(fd, buffer, len - 1, 0); + n = recv(fd, buffer, len - 1, 0); if (n < 0 && errno != 11) { printf_error("%s ERROR: error reading from %s:%d: %s%s\n", COL_RED, options->host, options->port, strerror(errno), RESET); @@ -567,7 +560,7 @@ int tcpConnect(struct sslCheckOptions *options) send(socketDescriptor, "\x00\x00\x00\x08\x04\xd2\x16\x2f", 8, 0); // Read reply byte - if (1 != recvall(socketDescriptor, &buffer, 1, 0)) { + if (1 != recv(socketDescriptor, &buffer, 1, 0)) { printf_error("%s ERROR: unexpected EOF reading from %s:%d%s\n", COL_RED, options->host, options->port, RESET); return 0; } @@ -591,7 +584,7 @@ int tcpConnect(struct sslCheckOptions *options) send(socketDescriptor, "\x03\x00\x00\x13\x0e\xe0\x00\x00\x00\x00\x00\x01\x00\x08\x00\x03\x00\x00\x00", 19, 0); // Read reply header - if (4 != recvall(socketDescriptor, buffer, 4, 0)) { + if (4 != recv(socketDescriptor, buffer, 4, 0)) { printf_error("%s ERROR: unexpected EOF reading from %s:%d%s\n", COL_RED, options->host, options->port, RESET); return 0; } @@ -605,7 +598,7 @@ int tcpConnect(struct sslCheckOptions *options) } // Read reply data - if (readlen != recvall(socketDescriptor, buffer, readlen, 0)) { + if (readlen != recv(socketDescriptor, buffer, readlen, 0)) { printf_error("%s ERROR: unexpected EOF reading from %s:%d%s\n", COL_RED, options->host, options->port, RESET); return 0; } @@ -824,7 +817,7 @@ int testCompression(struct sslCheckOptions *options, const SSL_METHOD *sslMethod int socketDescriptor = 0; SSL *ssl = NULL; BIO *cipherConnectionBio; - SSL_SESSION session; + SSL_SESSION *session; // Connect to host socketDescriptor = tcpConnect(options); @@ -874,16 +867,16 @@ int testCompression(struct sslCheckOptions *options, const SSL_METHOD *sslMethod // Connect SSL over socket SSL_connect(ssl); - session = *SSL_get_session(ssl); + session = SSL_get_session(ssl); #ifndef OPENSSL_NO_COMP // Make sure zlib is actually present - if (COMP_zlib()->type != NID_undef) + if (sk_SSL_COMP_num(SSL_COMP_get_compression_methods()) != 0) { printf_xml(" \n", - session.compress_meth); + SSL_SESSION_get_compress_id(session)); - if (session.compress_meth == 0) + if (SSL_SESSION_get_compress_id(session) == 0) { printf("Compression %sdisabled%s\n\n", COL_GREEN, RESET); } @@ -1018,19 +1011,23 @@ int testFallback(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) if (!downgraded) { sslversion = SSL_version(ssl); + if (sslversion == TLS1_3_VERSION) + { + secondMethod = TLSv1_2_client_method(); + } #if OPENSSL_VERSION_NUMBER >= 0x10001000L if (sslversion == TLS1_2_VERSION) { secondMethod = TLSv1_1_client_method(); - } - else if (sslversion == TLS1_1_VERSION) - { - secondMethod = TLSv1_client_method(); } else #endif if (sslversion == TLS1_VERSION) { - printf("Server only supports TLSv1.0\n\n"); + secondMethod = TLSv1_client_method(); + } + else if (sslversion == TLS1_VERSION) + { + printf("Server only supports TLSv1.0"); status = false; } else @@ -1042,7 +1039,6 @@ int testFallback(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) else { printf("Server %sdoes not%s support TLS Fallback SCSV\n\n", COL_RED, RESET); - printf_xml(" \n"); } } else @@ -1055,7 +1051,6 @@ int testFallback(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) if (SSL_get_error(ssl, connStatus == 6)) { printf("Server %ssupports%s TLS Fallback SCSV\n\n", COL_GREEN, RESET); - printf_xml(" \n"); status = false; } } @@ -1187,10 +1182,11 @@ int testRenegotiation(struct sslCheckOptions *options, const SSL_METHOD *sslMeth /* Yes, we know what we are doing here. No, we do not treat a renegotiation * as authenticating any earlier-received data. */ - if (use_unsafe_renegotiation_flag) { +/* if (use_unsafe_renegotiation_flag) { printf_verbose("use_unsafe_renegotiation_flag\n"); - ssl->s3->flags |= SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; - } + SSL_CTX_set_options(ssl,SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); + SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION?? + } */ if (use_unsafe_renegotiation_op) { printf_verbose("use_unsafe_renegotiation_op\n"); SSL_set_options(ssl, @@ -1226,14 +1222,14 @@ int testRenegotiation(struct sslCheckOptions *options, const SSL_METHOD *sslMeth printf_verbose("Attempting SSL_do_handshake(ssl)\n"); SSL_do_handshake(ssl); // Send renegotiation request to server //TODO :: XXX hanging here - if (SSL_get_state(ssl) == SSL_ST_OK) + if (SSL_get_state(ssl) == TLS_ST_OK) { res = SSL_do_handshake(ssl); // Send renegotiation request to server if( res != 1 ) { printf_error("\n\nSSL_do_handshake() call failed\n"); } - if (SSL_get_state(ssl) == SSL_ST_OK) + if (SSL_get_state(ssl) == TLS_ST_OK) { /* our renegotiation is complete */ renOut->supported = true; @@ -1319,11 +1315,12 @@ const char* printableSslMethod(const SSL_METHOD *sslMethod) if (sslMethod == TLSv1_2_client_method()) return "TLSv1.2"; #endif + if (sslMethod == TLSv1_3_client_method()) + return "TLSv1.3"; return "unknown SSL_METHOD"; } // Test for Heartbleed - int testHeartbleed(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) { // Variables... @@ -1354,6 +1351,10 @@ int testHeartbleed(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) hello[10] = 0x03; } #endif + else if (sslMethod == TLSv1_3_client_method()) + { + hello[10] = 0x03; + } if (send(socketDescriptor, hello, sizeof(hello), 0) <= 0) { printf_error("send() failed: %s\n", strerror(errno)); exit(1); @@ -1375,6 +1376,10 @@ int testHeartbleed(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) hb[2] = 0x03; } #endif + else if (sslMethod == TLSv1_3_client_method()) + { + hb[2] = 0x03; + } if (send(socketDescriptor, hb, sizeof(hb), 0) <= 0) { printf_error("send() failed: %s\n", strerror(errno)); exit(1); @@ -1387,7 +1392,7 @@ int testHeartbleed(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) memset(hbbuf, 0, sizeof(hbbuf)); // Read 5 byte header - int readResult = recvall(socketDescriptor, hbbuf, 5, 0); + int readResult = recv(socketDescriptor, hbbuf, 5, 0); if (readResult <= 0) { break; @@ -1406,7 +1411,7 @@ int testHeartbleed(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) memset(hbbuf, 0, sizeof(hbbuf)); // Read rest of record - readResult = recvall(socketDescriptor, hbbuf, ln, 0); + readResult = recv(socketDescriptor, hbbuf, ln, 0); if (readResult <= 0) { break; @@ -1504,6 +1509,39 @@ int ssl_print_tmp_key(struct sslCheckOptions *options, SSL *s) return 0; } +int setCipherSuite(struct sslCheckOptions *options, const SSL_METHOD *sslMethod, const char *str) +{ + if(strlen(str)>0) + { + if(sslMethod==TLSv1_3_client_method()) + { + return(SSL_CTX_set_ciphersuites(options->ctx,str)); + } + else + { + return(SSL_CTX_set_cipher_list(options->ctx,str)); + } + } +} + +char *cipherRemove(char *str, const char *sub) { + char *p, *q, *r; + if ((q = r = strstr(str, sub)) != NULL) { + size_t len = strlen(sub)+1; + if(q != str) + { + q--; + r--; + } + while ((r = strstr(p = r + len, sub)) != NULL) { + while (p < r) + *q++ = *p++; + } + while ((*q++ = *p++) != '\0') + continue; + } + return str; +} // Test a cipher... int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) @@ -1521,18 +1559,16 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) char hexCipherId[10]; int resultSize = 0; int cipherbits; - char *strength; uint32_t cipherid; const SSL_CIPHER *sslCipherPointer; const char *cleanSslMethod = printableSslMethod(sslMethod); + char *ciphername; struct timeval tval_start, tval_end, tval_elapsed; if (options->showTimes) { gettimeofday(&tval_start, NULL); } - - // Create request buffer... memset(requestBuffer, 0, 200); snprintf(requestBuffer, 199, "GET / HTTP/1.0\r\nUser-Agent: SSLScan\r\nHost: %s\r\n\r\n", options->host); @@ -1541,13 +1577,11 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) socketDescriptor = tcpConnect(options); if (socketDescriptor != 0) { - if (SSL_CTX_set_cipher_list(options->ctx, options->cipherstring) != 0) + if (setCipherSuite(options, sslMethod, options->cipherstring)) { - // Create SSL object... ssl = SSL_new(options->ctx); - if (ssl != NULL) { // Connect socket and BIO @@ -1569,24 +1603,11 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) if (cipherStatus == 0) { - SSL_free(ssl); return false; } else if (cipherStatus != 1) { - tempInt = SSL_get_error(ssl, cipherStatus); - printf_verbose("SSL_get_error(ssl, cipherStatus) returned: %d (%s)\n", tempInt, SSL_ERR_to_string(tempInt)); - - // I'd rather use ERR_print_errors(BIO) instead of this loop, but it needs a BIO for stdout/stderr which we - // don't have yet. - while (ERR_peek_error() > 0) - { - printf_verbose("[%s:%s@%d]:%s\n", __FILE__, __func__, __LINE__, ERR_error_string(ERR_peek_error(), NULL)); - // Dequeue the error, since we only peeked at it. Can't put this in the line above or we'll loop - // forever when not in verbose mode. - ERR_get_error(); - } - SSL_free(ssl); + printf_verbose("SSL_get_error(ssl, cipherStatus) said: %d\n", SSL_get_error(ssl, cipherStatus)); return false; } @@ -1597,7 +1618,7 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) printf_xml(" cipherstring, "ALL:eNULL")) + if (strcmp(options->cipherstring, "ALL:eNULL") && strcmp(options->cipherstring, "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256")) { printf_xml("accepted\""); printf("Accepted "); @@ -1703,38 +1724,38 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) { printf("%8s ", hexCipherId); } - - printf_xml(" bits=\"%d\" cipher=\"%s\" id=\"%s\"", cipherbits, sslCipherPointer->name, hexCipherId); - if (strstr(sslCipherPointer->name, "NULL")) + + ciphername=SSL_CIPHER_get_name(sslCipherPointer); + + printf_xml(" bits=\"%d\" cipher=\"%s\" id=\"%s\"", cipherbits, ciphername, hexCipherId); + if (strstr(ciphername, "NULL")) { - printf("%s%-29s%s", COL_RED_BG, sslCipherPointer->name, RESET); - strength = "null"; + printf("%s%-29s%s", COL_RED_BG, ciphername, RESET); } - else if (strstr(sslCipherPointer->name, "ADH") || strstr(sslCipherPointer->name, "AECDH")) + else if (strstr(ciphername, "ADH") || strstr(ciphername, "AECDH")) { - printf("%s%-29s%s", COL_PURPLE, sslCipherPointer->name, RESET); - strength = "anonymous"; + printf("%s%-29s%s", COL_PURPLE, ciphername, RESET); } - else if (strstr(sslCipherPointer->name, "EXP")) + else if (strstr(ciphername, "EXP") +#ifndef OPENSSL_NO_SSL3 + || (strcmp(cleanSslMethod, "SSLv3") == 0 && !strstr(ciphername, "RC4")) +#endif + ) { - printf("%s%-29s%s", COL_RED, sslCipherPointer->name, RESET); - strength = "weak"; + printf("%s%-29s%s", COL_RED, ciphername, RESET); } - else if (strstr(sslCipherPointer->name, "RC4") || strstr(sslCipherPointer->name, "DES")) + else if (strstr(ciphername, "RC4") || strstr(ciphername, "DES")) { - printf("%s%-29s%s", COL_YELLOW, sslCipherPointer->name, RESET); - strength = "medium"; + printf("%s%-29s%s", COL_YELLOW, ciphername, RESET); } - else if ((strstr(sslCipherPointer->name, "CHACHA20") || (strstr(sslCipherPointer->name, "GCM"))) - && strstr(sslCipherPointer->name, "DHE")) + else if ((strstr(ciphername, "CHACHA20") || (strstr(ciphername, "GCM"))) + && strstr(ciphername, "DHE")) { - printf("%s%-29s%s", COL_GREEN, sslCipherPointer->name, RESET); - strength = "strong"; + printf("%s%-29s%s", COL_GREEN, ciphername, RESET); } else { - printf("%-29s", sslCipherPointer->name); - strength = "acceptable"; + printf("%-29s", ciphername); } if (options->cipher_details == true) @@ -1753,13 +1774,21 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) } printf("\n"); - printf_xml(" strength=\"%s\" />\n", strength); + printf_xml(" />\n"); // Disconnect SSL over socket if (cipherStatus == 1) { + char *usedcipher = SSL_get_cipher_name(ssl); + if(sslMethod==TLSv1_3_client_method()) + { // Remove cipher from TLSv1.3 list + cipherRemove(options->cipherstring, usedcipher); + } + else + { strncat(options->cipherstring, ":!", 2); - strncat(options->cipherstring, SSL_get_cipher_name(ssl), strlen(SSL_get_cipher_name(ssl))); + strncat(options->cipherstring, usedcipher, strlen(usedcipher)); + } SSL_shutdown(ssl); } @@ -1834,6 +1863,8 @@ int checkCertificate(struct sslCheckOptions *options, const SSL_METHOD *sslMetho EVP_PKEY *publicKey = NULL; char certAlgorithm[80]; X509_EXTENSION *extension = NULL; + const X509_ALGOR *palg = NULL; + const ASN1_OBJECT *paobj = NULL; // Connect to host socketDescriptor = tcpConnect(options); @@ -1914,27 +1945,27 @@ int checkCertificate(struct sslCheckOptions *options, const SSL_METHOD *sslMetho if (!(X509_FLAG_COMPAT & X509_FLAG_NO_SIGNAME)) { printf("Signature Algorithm: "); - i2t_ASN1_OBJECT(certAlgorithm, sizeof(certAlgorithm), x509Cert->cert_info->signature->algorithm); + X509_get0_signature(NULL, &palg, x509Cert); + X509_ALGOR_get0(&paobj, NULL, NULL, palg); + OBJ_obj2txt(certAlgorithm, sizeof(certAlgorithm), paobj, 0); strtok(certAlgorithm, "\n"); if (strstr(certAlgorithm, "md5") || strstr(certAlgorithm, "sha1")) { - printf_xml(" "); printf("%s%s%s\n", COL_RED, certAlgorithm, RESET); } else if (strstr(certAlgorithm, "sha512") || strstr(certAlgorithm, "sha256")) { - printf_xml(" "); printf("%s%s%s\n", COL_GREEN, certAlgorithm, RESET); } else { - printf_xml(" "); printf("%s\n", certAlgorithm); } if (options->xmlOutput) { - i2a_ASN1_OBJECT(fileBIO, x509Cert->cert_info->signature->algorithm); + printf_xml(" "); + X509_signature_print(fileBIO, palg, NULL); printf_xml("\n"); } } @@ -1950,28 +1981,26 @@ int checkCertificate(struct sslCheckOptions *options, const SSL_METHOD *sslMetho } else { - switch (publicKey->type) + keyBits=EVP_PKEY_bits(publicKey); + switch (EVP_PKEY_id(publicKey)) { case EVP_PKEY_RSA: - if (publicKey->pkey.rsa) + if (EVP_PKEY_get1_RSA(publicKey)!=NULL) { - keyBits = BN_num_bits(publicKey->pkey.rsa->n); - printf_xml(" pkey.rsa->n)); if (keyBits < 2048 ) { printf("RSA Key Strength: %s%d%s\n", COL_RED, keyBits, RESET); - printf_xml("strength=\"weak\" />\n"); } else if (keyBits >= 4096 ) { printf("RSA Key Strength: %s%d%s\n", COL_GREEN, keyBits, RESET); - printf_xml("strength=\"strong\" />\n"); } else { printf("RSA Key Strength: %d\n", keyBits); - printf_xml("strength=\"acceptable\" />\n"); } + + printf_xml(" \n", keyBits); } else { @@ -1980,7 +2009,7 @@ int checkCertificate(struct sslCheckOptions *options, const SSL_METHOD *sslMetho printf("\n"); break; case EVP_PKEY_DSA: - if (publicKey->pkey.dsa) + if (EVP_PKEY_get1_DSA(publicKey)!=NULL) { // TODO - display key strength printf_xml(" \n"); @@ -1992,7 +2021,7 @@ int checkCertificate(struct sslCheckOptions *options, const SSL_METHOD *sslMetho } break; case EVP_PKEY_EC: - if (publicKey->pkey.ec) + if (EVP_PKEY_get1_EC_KEY(publicKey)) { // TODO - display key strength printf_xml(" \n"); @@ -2048,23 +2077,23 @@ int checkCertificate(struct sslCheckOptions *options, const SSL_METHOD *sslMetho // Get certificate altnames if supported if (!(X509_FLAG_COMPAT & X509_FLAG_NO_EXTENSIONS)) { - if (sk_X509_EXTENSION_num(x509Cert->cert_info->extensions) > 0) + if (sk_X509_EXTENSION_num(X509_get0_extensions(x509Cert)) > 0) { cnindex = X509_get_ext_by_NID (x509Cert, NID_subject_alt_name, -1); if (cnindex != -1) { - extension = X509v3_get_ext(x509Cert->cert_info->extensions,cnindex); + extension = X509v3_get_ext(X509_get0_extensions(x509Cert),cnindex); printf("Altnames: "); if (!X509V3_EXT_print(stdoutBIO, extension, X509_FLAG_COMPAT, 0)) { - M_ASN1_OCTET_STRING_print(stdoutBIO, extension->value); + ASN1_STRING_print(stdoutBIO, X509_EXTENSION_get_data(extension)); } if (options->xmlOutput) { printf_xml(" value); + ASN1_STRING_print(fileBIO, X509_EXTENSION_get_data(extension)); } printf_xml("]]>\n"); printf("\n"); @@ -2253,6 +2282,10 @@ int ocspRequest(struct sslCheckOptions *options) sslMethod = TLSv1_2_method(); } #endif + else if( options->sslVersion == tls_v13) { + printf_verbose("sslMethod = TLSv1_3_method()"); + sslMethod = TLSv1_3_method(); + } else { printf_verbose("sslMethod = TLSv1_method()\n"); printf_verbose("If server doesn't support TLSv1.0, manually specify TLS version\n"); @@ -2368,119 +2401,22 @@ static int ocsp_resp_cb(SSL *s, void *arg) int len; OCSP_RESPONSE *rsp; len = SSL_get_tlsext_status_ocsp_resp(s, &p); - if (!p) { - printf("No OCSP response sent\n\n"); + BIO_puts(arg, "OCSP response: "); + if (p == NULL) { + BIO_puts(arg, "no response sent\n"); return 1; } rsp = d2i_OCSP_RESPONSE(NULL, &p, len); - if (!rsp){ - printf("OCSP response parse error\n"); + if (rsp == NULL) { + BIO_puts(arg, "response parse error\n"); + BIO_dump_indent(arg, (char *)p, len, 4); return 0; } - - BIO *bio_out; - bio_out = BIO_new_fp(stdout, BIO_NOCLOSE); - - int i = 0; - long l; - OCSP_CERTID *cid = NULL; - OCSP_BASICRESP *br = NULL; - OCSP_RESPID *rid = NULL; - OCSP_RESPDATA *rd = NULL; - OCSP_CERTSTATUS *cst = NULL; - OCSP_REVOKEDINFO *rev = NULL; - OCSP_SINGLERESP *single = NULL; - OCSP_RESPBYTES *rb = rsp->responseBytes; - - //Pretty print response status - l = ASN1_ENUMERATED_get(rsp->responseStatus); - if (BIO_printf(bio_out, "OCSP Response Status: %s (0x%lx)\n", - OCSP_response_status_str(l), l) <= 0) - goto err; - - //Check for null response bytes - if (rb == NULL) - return 1; - i = ASN1_STRING_length(rb->response); - if ((br = OCSP_response_get1_basic(rsp)) == NULL) - goto err; - rd = br->tbsResponseData; - l = ASN1_INTEGER_get(rd->version); - - //Pretty print responder id - if(BIO_puts(bio_out, "Responder Id: ") <= 0) - goto err; - rid = rd->responderId; - switch (rid->type){ - case V_OCSP_RESPID_NAME: - X509_NAME_print_ex(bio_out, rid->value.byName, 0, XN_FLAG_ONELINE); - break; - case V_OCSP_RESPID_KEY: - i2a_ASN1_STRING(bio_out, rid->value.byKey, V_ASN1_OCTET_STRING); - break; - } - - if(BIO_printf(bio_out, "\nProduced At: ") <= 0) - goto err; - if (!ASN1_GENERALIZEDTIME_print(bio_out, rd->producedAt)) - goto err; - if (BIO_printf(bio_out, "\nResponses:\n") <= 0) - goto err; - for (i = 0; i < sk_OCSP_SINGLERESP_num(rd->responses); i++) - { - if (!sk_OCSP_SINGLERESP_value(rd->responses, i)) - continue; - single = sk_OCSP_SINGLERESP_value(rd->responses, i); - cid = single->certId; - if (ocsp_certid_print(bio_out, cid, 4) <= 0) - goto err; - cst = single->certStatus; - if (cst->type == V_OCSP_CERTSTATUS_GOOD) - { - if (BIO_printf(bio_out, "Cert Status: %s%s%s\n\n", - COL_GREEN, OCSP_cert_status_str(cst->type), RESET) <= 0) - goto err; - } - else if (cst->type == V_OCSP_CERTSTATUS_UNKNOWN) - { - if (BIO_printf(bio_out, "Cert Status: %s%s%s\n\n", - COL_YELLOW, OCSP_cert_status_str(cst->type), RESET) <= 0) - goto err; - } - else - { - rev = cst->value.revoked; - if (BIO_printf(bio_out, "\nRevocation Time: \n\n") <= 0) - goto err; - if (!ASN1_GENERALIZEDTIME_print(bio_out, rev->revocationTime)) - goto err; - if (rev->revocationReason) { - l = ASN1_ENUMERATED_get(rev->revocationReason); - if (BIO_printf(bio_out, - "\nRevocation Reason: %s (0x%lx)\n\n", - OCSP_crl_reason_str(l), l) <= 0) - goto err; - } - } - } - err: + BIO_puts(arg, "\n======================================\n"); + OCSP_RESPONSE_print(arg, rsp, 0); + BIO_puts(arg, "======================================\n"); OCSP_RESPONSE_free(rsp); return 1; - -} - -int ocsp_certid_print(BIO *bp, OCSP_CERTID *a, int indent) -{ - BIO_printf(bp, "%*sHash Algorithm: ", indent, ""); - i2a_ASN1_OBJECT(bp, a->hashAlgorithm->algorithm); - BIO_printf(bp, "\n%*sIssuer Name Hash: ", indent, ""); - i2a_ASN1_STRING(bp, a->issuerNameHash, V_ASN1_OCTET_STRING); - BIO_printf(bp, "\n%*sIssuer Key Hash: ", indent, ""); - i2a_ASN1_STRING(bp, a->issuerKeyHash, V_ASN1_OCTET_STRING); - BIO_printf(bp, "\n%*sSerial Number: ", indent, ""); - i2a_ASN1_INTEGER(bp, a->serialNumber); - BIO_printf(bp, "\n"); - return 1; } // Print out the full certificate @@ -2524,10 +2460,14 @@ int showCertificate(struct sslCheckOptions *options) printf_verbose("sslMethod = TLSv1_2_method()"); sslMethod = TLSv1_2_method(); } + else if( options->sslVersion == tls_v13) { + printf_verbose("sslMethod = TLSv1_3_method()"); + sslMethod = TLSv1_3_method(); + } #endif else { printf_verbose("sslMethod = TLSv1_method()\n"); - printf_verbose("If server doesn't support TLSv1.0, manually specify TLS version\n"); + printf_verbose("If server doesn't support TLSv1.0, manually specificy TLS version\n"); sslMethod = TLSv1_method(); } options->ctx = SSL_CTX_new(sslMethod); @@ -2600,6 +2540,8 @@ int showCertificate(struct sslCheckOptions *options) //SSL_set_verify(ssl, SSL_VERIFY_NONE|SSL_VERIFY_CLIENT_ONCE, NULL); + //X509_print_ex(bp, x509Cert, 0, 0); + // Cert Version if (!(X509_FLAG_COMPAT & X509_FLAG_NO_VERSION)) { @@ -2683,13 +2625,15 @@ int showCertificate(struct sslCheckOptions *options) // Signature Algo... if (!(X509_FLAG_COMPAT & X509_FLAG_NO_SIGNAME)) { - printf(" Signature Algorithm: "); - i2a_ASN1_OBJECT(stdoutBIO, x509Cert->cert_info->signature->algorithm); + X509_signature_print(stdoutBIO, X509_get0_tbs_sigalg(x509Cert), NULL); +/* printf(" Signature Algorithm: "); + i2a_ASN1_OBJECT(stdoutBIO, X509_get0_tbs_sigalg(x509Cert)); printf("\n"); +*/ if (options->xmlOutput) { printf_xml(" "); - i2a_ASN1_OBJECT(fileBIO, x509Cert->cert_info->signature->algorithm); + i2a_ASN1_OBJECT(fileBIO, X509_get0_tbs_sigalg(x509Cert)); printf_xml("\n"); } } @@ -2736,12 +2680,13 @@ int showCertificate(struct sslCheckOptions *options) if (!(X509_FLAG_COMPAT & X509_FLAG_NO_PUBKEY)) { printf(" Public Key Algorithm: "); - i2a_ASN1_OBJECT(stdoutBIO, x509Cert->cert_info->key->algor->algorithm); + ASN1_OBJECT *xpoid; + i2a_ASN1_OBJECT(stdoutBIO, xpoid); printf("\n"); if (options->xmlOutput) { printf_xml(" "); - i2a_ASN1_OBJECT(fileBIO, x509Cert->cert_info->key->algor->algorithm); + i2a_ASN1_OBJECT(fileBIO, xpoid); printf_xml("\n"); } @@ -2754,17 +2699,17 @@ int showCertificate(struct sslCheckOptions *options) } else { - switch (publicKey->type) + switch (EVP_PKEY_id(publicKey)) { case EVP_PKEY_RSA: - if (publicKey->pkey.rsa) + if (EVP_PKEY_get1_RSA(publicKey)!=NULL) { - printf(" RSA Public Key: (%d bit)\n", BN_num_bits(publicKey->pkey.rsa->n)); - printf_xml(" \n", BN_num_bits(publicKey->pkey.rsa->n)); - RSA_print(stdoutBIO, publicKey->pkey.rsa, 6); + printf(" RSA Public Key: (%d bit)\n", EVP_PKEY_bits(publicKey)); + printf_xml(" \n", EVP_PKEY_bits(publicKey)); + RSA_print(stdoutBIO, EVP_PKEY_get1_RSA(publicKey), 6); if (options->xmlOutput) { - RSA_print(fileBIO, publicKey->pkey.rsa, 4); + RSA_print(fileBIO, EVP_PKEY_get1_RSA(publicKey), 4); printf_xml(" \n"); } } @@ -2774,14 +2719,14 @@ int showCertificate(struct sslCheckOptions *options) } break; case EVP_PKEY_DSA: - if (publicKey->pkey.dsa) + if (EVP_PKEY_get1_DSA(publicKey)!=NULL) { printf(" DSA Public Key:\n"); printf_xml(" \n"); - DSA_print(stdoutBIO, publicKey->pkey.dsa, 6); + DSA_print(stdoutBIO, EVP_PKEY_get1_DSA(publicKey), 6); if (options->xmlOutput) { - DSA_print(fileBIO, publicKey->pkey.dsa, 4); + DSA_print(fileBIO, EVP_PKEY_get1_DSA(publicKey), 4); printf_xml(" \n"); } } @@ -2791,14 +2736,14 @@ int showCertificate(struct sslCheckOptions *options) } break; case EVP_PKEY_EC: - if (publicKey->pkey.ec) + if (EVP_PKEY_get1_EC_KEY(publicKey)!=NULL) { printf(" EC Public Key:\n"); printf_xml(" \n"); - EC_KEY_print(stdoutBIO, publicKey->pkey.ec, 6); + EC_KEY_print(stdoutBIO, EVP_PKEY_get1_EC_KEY(publicKey), 6); if (options->xmlOutput) { - EC_KEY_print(fileBIO, publicKey->pkey.ec, 4); + EC_KEY_print(fileBIO, EVP_PKEY_get1_EC_KEY(publicKey), 4); printf_xml(" \n"); } } @@ -2820,14 +2765,14 @@ int showCertificate(struct sslCheckOptions *options) // X509 v3... if (!(X509_FLAG_COMPAT & X509_FLAG_NO_EXTENSIONS)) { - if (sk_X509_EXTENSION_num(x509Cert->cert_info->extensions) > 0) + if (sk_X509_EXTENSION_num(X509_get0_extensions(x509Cert)) > 0) { printf(" X509v3 Extensions:\n"); printf_xml(" \n"); - for (tempInt = 0; tempInt < sk_X509_EXTENSION_num(x509Cert->cert_info->extensions); tempInt++) + for (tempInt = 0; tempInt < sk_X509_EXTENSION_num(X509_get0_extensions(x509Cert)); tempInt++) { // Get Extension... - extension = sk_X509_EXTENSION_value(x509Cert->cert_info->extensions, tempInt); + extension = sk_X509_EXTENSION_value(X509_get0_extensions(x509Cert), tempInt); // Print Extension name... printf(" "); @@ -2846,12 +2791,12 @@ int showCertificate(struct sslCheckOptions *options) if (!X509V3_EXT_print(stdoutBIO, extension, X509_FLAG_COMPAT, 8)) { printf(" "); - M_ASN1_OCTET_STRING_print(stdoutBIO, extension->value); + ASN1_STRING_print(stdoutBIO, X509_EXTENSION_get_data(extension)); } if (options->xmlOutput) { if (!X509V3_EXT_print(fileBIO, extension, X509_FLAG_COMPAT, 0)) - M_ASN1_OCTET_STRING_print(fileBIO, extension->value); + ASN1_STRING_print(stdoutBIO, X509_EXTENSION_get_data(extension)); printf_xml("]]>\n"); } printf("\n"); @@ -2967,10 +2912,14 @@ int showTrustedCAs(struct sslCheckOptions *options) printf_verbose("sslMethod = TLSv1_2_method()"); sslMethod = TLSv1_2_method(); } + else if( options->sslVersion == tls_v13) { + printf_verbose("sslMethod = TLSv1_3_method()"); + sslMethod = TLSv1_3_method(); + } #endif else { printf_verbose("sslMethod = TLSv1_method()\n"); - printf_verbose("If server doesn't support TLSv1.0, manually specify TLS version\n"); + printf_verbose("If server doesn't support TLSv1.0, manually specificy TLS version\n"); sslMethod = TLSv1_method(); } options->ctx = SSL_CTX_new(sslMethod); @@ -3162,6 +3111,11 @@ int testProtocolCiphers(struct sslCheckOptions *options, const SSL_METHOD *sslMe { int status; status = true; + + //strncpy(options->cipherstring, "", 1); + if(sslMethod==TLSv1_3_client_method()) + strncpy(options->cipherstring, "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256", 122); + else strncpy(options->cipherstring, "ALL:eNULL", 10); // Loop until the server won't accept any more ciphers @@ -3171,13 +3125,16 @@ int testProtocolCiphers(struct sslCheckOptions *options, const SSL_METHOD *sslMe options->ctx = SSL_CTX_new(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); + // minimal protocol version + if(sslMethod==TLSv1_3_client_method()) + SSL_CTX_set_min_proto_version(options->ctx, TLS1_3_VERSION); + // Load Certs if required... if ((options->clientCertsFile != 0) || (options->privateKeyFile != 0)) status = loadCerts(options); @@ -3225,6 +3182,7 @@ int testHost(struct sslCheckOptions *options) switch (options->sslVersion) { case ssl_all: + populateCipherList(options, TLSv1_3_client_method()); #if OPENSSL_VERSION_NUMBER >= 0x10001000L populateCipherList(options, TLSv1_2_client_method()); populateCipherList(options, TLSv1_1_client_method()); @@ -3238,12 +3196,16 @@ int testHost(struct sslCheckOptions *options) #endif break; case tls_all: + populateCipherList(options, TLSv1_3_client_method()); #if OPENSSL_VERSION_NUMBER >= 0x10001000L populateCipherList(options, TLSv1_2_client_method()); populateCipherList(options, TLSv1_1_client_method()); #endif populateCipherList(options, TLSv1_client_method()); break; + case tls_v13: + populateCipherList(options, TLSv1_3_client_method()); + break; #if OPENSSL_VERSION_NUMBER >= 0x10001000L case tls_v12: populateCipherList(options, TLSv1_2_client_method()); @@ -3303,6 +3265,11 @@ int testHost(struct sslCheckOptions *options) { printf(" %sHeartbleed:%s\n", COL_BLUE, RESET); #if OPENSSL_VERSION_NUMBER >= 0x10001000L + if( options->sslVersion == ssl_all || options->sslVersion == tls_all || options->sslVersion == tls_v13) + { + printf("TLS 1.3 "); + status = testHeartbleed(options, TLSv1_3_client_method()); + } if( options->sslVersion == ssl_all || options->sslVersion == tls_all || options->sslVersion == tls_v12) { printf("TLS 1.2 "); @@ -3343,6 +3310,8 @@ int testHost(struct sslCheckOptions *options) switch (options->sslVersion) { case ssl_all: + if (status != false) + status = testProtocolCiphers(options, TLSv1_3_client_method()); #if OPENSSL_VERSION_NUMBER >= 0x10001000L if (status != false) status = testProtocolCiphers(options, TLSv1_2_client_method()); @@ -3371,6 +3340,8 @@ int testHost(struct sslCheckOptions *options) break; #endif case tls_all: + if (status != false) + status = testProtocolCiphers(options, TLSv1_3_client_method()); #if OPENSSL_VERSION_NUMBER >= 0x10001000L if (status != false) status = testProtocolCiphers(options, TLSv1_2_client_method()); @@ -3390,6 +3361,9 @@ int testHost(struct sslCheckOptions *options) case tls_v12: status = testProtocolCiphers(options, TLSv1_2_client_method()); break; + case tls_v13: + status = testProtocolCiphers(options, TLSv1_3_client_method()); + break; #endif } } @@ -3436,35 +3410,6 @@ int testHost(struct sslCheckOptions *options) return status; } -// Return a string description of an SSL error. -// It would be nice if there were a standard function for this... -const char *SSL_ERR_to_string (int sslerr) -{ - switch (sslerr) - { - // Values taken from openssl/ssl.h - case SSL_ERROR_NONE: - return "SSL_ERROR_NONE"; - case SSL_ERROR_SSL: - return "SSL_ERROR_SSL"; - case SSL_ERROR_WANT_READ: - return "SSL_ERROR_WANT_READ"; - case SSL_ERROR_WANT_WRITE: - return "SSL_ERROR_WANT_WRITE"; - case SSL_ERROR_WANT_X509_LOOKUP: - return "SSL_ERROR_WANT_X509_LOOKUP"; - case SSL_ERROR_SYSCALL: - return "SSL_ERROR_SYSCALL"; - case SSL_ERROR_ZERO_RETURN: - return "SSL_ERROR_ZERO_RETURN"; - case SSL_ERROR_WANT_CONNECT: - return "SSL_ERROR_WANT_CONNECT"; - case SSL_ERROR_WANT_ACCEPT: - return "SSL_ERROR_WANT_ACCEPT"; - default: - return "SSL_ERROR_UNKNOWN"; - } -} int main(int argc, char *argv[]) { @@ -3714,6 +3659,9 @@ int main(int argc, char *argv[]) // TLS v12 only... else if (strcmp("--tls12", argv[argLoop]) == 0) options.sslVersion = tls_v12; + // TLS v13 only... + else if (strcmp("--tls13", argv[argLoop]) == 0) + options.sslVersion = tls_v13; #endif // TLS (all versions)... else if (strcmp("--tlsall", argv[argLoop]) == 0) @@ -3945,6 +3893,7 @@ int main(int argc, char *argv[]) #if OPENSSL_VERSION_NUMBER >= 0x10001000L printf(" %s--tls11%s Only check TLSv1.1 ciphers\n", COL_GREEN, RESET); printf(" %s--tls12%s Only check TLSv1.2 ciphers\n", COL_GREEN, RESET); + printf(" %s--tls13%s Only check TLSv1.3 ciphers\n", COL_GREEN, RESET); #endif printf(" %s--tlsall%s Only check TLS ciphers (all versions)\n", COL_GREEN, RESET); printf(" %s--ocsp%s Request OCSP response from server\n", COL_GREEN, RESET); @@ -4008,7 +3957,7 @@ int main(int argc, char *argv[]) printf("\t\t%sTLSv1.2 ciphers will not be detected%s\n", COL_RED, RESET); #endif - SSLeay_add_all_algorithms(); + //SSLeay_add_all_algorithms(); ERR_load_crypto_strings(); // Do the testing... diff --git a/sslscan.h b/sslscan.h index be9a63e..bb48636 100644 --- a/sslscan.h +++ b/sslscan.h @@ -55,6 +55,7 @@ #define tls_v10 4 #define tls_v11 5 #define tls_v12 6 +#define tls_v13 7 // Macros for various outputs #define printf(format, ...) if (!xml_to_stdout) fprintf(stdout, format, ##__VA_ARGS__) @@ -193,7 +194,6 @@ void readLine(FILE *, char *, int); ssize_t sendString(int, const char[]); int readOrLogAndClose(int, void *, size_t, const struct sslCheckOptions *); const char *printableSslMethod(const SSL_METHOD *); -const char *SSL_ERR_to_string (int sslerr); static int password_callback(char *, int, int, void *); int ssl_print_tmp_key(struct sslCheckOptions *, SSL *s); static int ocsp_resp_cb(SSL *s, void *arg); From 9e97f08b83d84c771fb756b69f1f49a9b318ceeb Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Mon, 28 Oct 2019 17:59:28 -0400 Subject: [PATCH 02/52] Now successfully compiles with OpenSSL v1.1.1. --- Makefile.mingw | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile.mingw b/Makefile.mingw index 70d4c5f..8357893 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -49,8 +49,8 @@ SECURITY_OPTIONS=-fstack-protector-all -D_FORTIFY_SOURCE=2 -Wformat -Wformat-sec # Turn on linker optimizations, and DEP support (--nxcompat) LINK_OPTIONS=-Wl,-O1 -Wl,--discard-all -Wl,--no-undefined -Wl,--dynamicbase -Wl,--nxcompat -static -CFLAGS += -Iopenssl_mingw/include -D__USE_GNU -LDFLAGS += -lws2_32 -lgdi32 +CFLAGS += -Iopenssl_mingw/include -D__USE_GNU -DOPENSSL_NO_SSL2 -Wno-deprecated-declarations +LDFLAGS += -lws2_32 -lgdi32 -lcrypt32 # Set the version string for the program. VERSION = "$(shell grep -E -o -m 1 "[0-9]+\.[0-9]+\.[0-9]+" Changelog) Windows $(ARCHITECTURE) (Mingw)" @@ -71,9 +71,9 @@ zlibpull: opensslpull: if [ -d openssl_mingw -a -d openssl_mingw/.git ]; then \ - cd ./openssl_mingw && git checkout OpenSSL_1_0_2-stable && git pull | grep -q "Already up-to-date." && [ -e ../.openssl_mingw.is.fresh ] || touch ../.openssl_mingw.is.fresh ; \ + cd ./openssl_mingw && git checkout OpenSSL_1_1_1-stable && git pull | grep -q "Already up-to-date." && [ -e ../.openssl_mingw.is.fresh ] || touch ../.openssl_mingw.is.fresh ; \ else \ - git clone --depth 1 -b OpenSSL_1_0_2-stable https://github.com/PeterMosmans/openssl ./openssl_mingw && cd ./openssl_mingw && touch ../.openssl_mingw.is.fresh ; \ + git clone --depth 1 -b OpenSSL_1_1_1-stable https://github.com/openssl/openssl ./openssl_mingw && cd ./openssl_mingw && touch ../.openssl_mingw.is.fresh ; \ fi zlib_mingw/libz.a: zlibpull From e4345fd6aada0a8b4d7db6dd031494279ee66bfa Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Mon, 28 Oct 2019 21:01:20 -0400 Subject: [PATCH 03/52] Now using Ubuntu 18 (bionic) in Travis CI. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5e14d66..b170fbe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ sudo: required -dist: trusty +dist: bionic language: c before_install: From 61048d5324aede52e9c4f4820e9427db48448b79 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Mon, 28 Oct 2019 21:13:36 -0400 Subject: [PATCH 04/52] Static builds now use OpenSSL v1.1.1. --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 227ea7b..48b0fd6 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ BINDIR = $(PREFIX)/bin MANDIR = $(PREFIX)/share/man MAN1DIR = $(MANDIR)/man1 -WARNINGS = -Wall -Wformat=2 -Wformat-security +WARNINGS = -Wall -Wformat=2 -Wformat-security -Wno-deprecated-declarations DEFINES = -DVERSION=\"$(GIT_VERSION)\" -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3 # for dynamic linking @@ -111,9 +111,9 @@ uninstall: true opensslpull: if [ -d openssl -a -d openssl/.git ]; then \ - cd ./openssl && git checkout OpenSSL_1_0_2-stable && git pull | grep -q "Already up-to-date." && [ -e ../.openssl.is.fresh ] || touch ../.openssl.is.fresh ; \ + cd ./openssl && git checkout OpenSSL_1_1_1-stable && git pull | grep -q "Already up-to-date." && [ -e ../.openssl.is.fresh ] || touch ../.openssl.is.fresh ; \ else \ - git clone --depth 1 -b OpenSSL_1_0_2-stable https://github.com/PeterMosmans/openssl ./openssl && cd ./openssl && touch ../.openssl.is.fresh ; \ + git clone --depth 1 -b OpenSSL_1_1_1-stable https://github.com/openssl/openssl ./openssl && cd ./openssl && touch ../.openssl.is.fresh ; \ fi # Need to build OpenSSL differently on OSX From 38dae15e25817e8e6ac3bd321c05130a95c0a5b8 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Mon, 28 Oct 2019 21:57:55 -0400 Subject: [PATCH 05/52] Fixed typo in OpenSSL configuration command. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 48b0fd6..78c1163 100644 --- a/Makefile +++ b/Makefile @@ -123,7 +123,7 @@ openssl/Makefile: .openssl.is.fresh # Any other *NIX platform else openssl/Makefile: .openssl.is.fresh - cd ./openssl; ./config -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIC no-shares enable-weak-ssl-ciphers enable-ssl2 zlib + cd ./openssl; ./config -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIC no-shared enable-weak-ssl-ciphers enable-ssl2 zlib endif openssl/libcrypto.a: openssl/Makefile From a89d06b55976972f563cd133d905232d25f68523 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Mon, 28 Oct 2019 22:11:36 -0400 Subject: [PATCH 06/52] Added -lpthread for static builds. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 78c1163..fdec4b8 100644 --- a/Makefile +++ b/Makefile @@ -58,7 +58,7 @@ ifeq ($(STATIC_BUILD), TRUE) PWD = $(shell pwd)/openssl LDFLAGS += -L${PWD}/ CFLAGS += -I${PWD}/include/ -I${PWD}/ -LIBS = -lssl -lcrypto -lz +LIBS = -lssl -lcrypto -lz -lpthread ifneq ($(OS), FreeBSD) LIBS += -ldl endif From ab97d943ea76a28890041c85593131ecf88ea8f5 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Mon, 28 Oct 2019 22:23:11 -0400 Subject: [PATCH 07/52] Re-enabled static builds with clang. --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index b170fbe..3877f5a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,8 +9,6 @@ before_install: script: - make sslscan CC=clang - make sslscan CC=gcc - # OpenSSL can't be compiled out-of-the box with clang, see - # http://wiki.openssl.org/index.php/Compilation_and_Installation#Modifying_Build_Settings - #- make static CC=clang + - make static CC=clang - make static CC=gcc - make -f Makefile.mingw From 2759c51f513e7b3b7bfd3f00f1804e62ef3dac1e Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Wed, 27 Nov 2019 01:11:13 -0500 Subject: [PATCH 08/52] Fixed compiler warnings. --- Makefile | 8 ++++---- sslscan.c | 34 +++++----------------------------- sslscan.h | 2 +- 3 files changed, 10 insertions(+), 34 deletions(-) diff --git a/Makefile b/Makefile index fdec4b8..9774976 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ MANDIR = $(PREFIX)/share/man MAN1DIR = $(MANDIR)/man1 WARNINGS = -Wall -Wformat=2 -Wformat-security -Wno-deprecated-declarations -DEFINES = -DVERSION=\"$(GIT_VERSION)\" -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3 +DEFINES = -DVERSION=\"$(GIT_VERSION)\" # for dynamic linking LIBS = -lssl -lcrypto @@ -119,17 +119,17 @@ opensslpull: # Need to build OpenSSL differently on OSX ifeq ($(OS), Darwin) openssl/Makefile: .openssl.is.fresh - cd ./openssl; ./Configure -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIC enable-ssl2 enable-weak-ssl-ciphers zlib darwin64-x86_64-cc + cd ./openssl; ./Configure -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIC enable-weak-ssl-ciphers zlib darwin64-x86_64-cc # Any other *NIX platform else openssl/Makefile: .openssl.is.fresh - cd ./openssl; ./config -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIC no-shared enable-weak-ssl-ciphers enable-ssl2 zlib + cd ./openssl; ./config -v -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIC no-shared enable-weak-ssl-ciphers zlib endif openssl/libcrypto.a: openssl/Makefile $(MAKE) -C openssl depend $(MAKE) -C openssl all - $(MAKE) -C openssl test +# $(MAKE) -C openssl test # Disabled because this takes 45+ minutes for OpenSSL v1.1.1. static: openssl/libcrypto.a $(MAKE) sslscan STATIC_BUILD=TRUE diff --git a/sslscan.c b/sslscan.c index 18374a2..aabcb6c 100644 --- a/sslscan.c +++ b/sslscan.c @@ -1299,10 +1299,6 @@ int testRenegotiation(struct sslCheckOptions *options, const SSL_METHOD *sslMeth const char* printableSslMethod(const SSL_METHOD *sslMethod) { -#ifndef OPENSSL_NO_SSL2 - if (sslMethod == SSLv2_client_method()) - return "SSLv2"; -#endif #ifndef OPENSSL_NO_SSL3 if (sslMethod == SSLv3_client_method()) return "SSLv3"; @@ -1522,6 +1518,7 @@ int setCipherSuite(struct sslCheckOptions *options, const SSL_METHOD *sslMethod, return(SSL_CTX_set_cipher_list(options->ctx,str)); } } + return 0; } char *cipherRemove(char *str, const char *sub) { @@ -1562,7 +1559,7 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) uint32_t cipherid; const SSL_CIPHER *sslCipherPointer; const char *cleanSslMethod = printableSslMethod(sslMethod); - char *ciphername; + const char *ciphername; struct timeval tval_start, tval_end, tval_elapsed; if (options->showTimes) { @@ -1779,7 +1776,7 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) // Disconnect SSL over socket if (cipherStatus == 1) { - char *usedcipher = SSL_get_cipher_name(ssl); + const char *usedcipher = SSL_get_cipher_name(ssl); if(sslMethod==TLSv1_3_client_method()) { // Remove cipher from TLSv1.3 list cipherRemove(options->cipherstring, usedcipher); @@ -2633,7 +2630,7 @@ int showCertificate(struct sslCheckOptions *options) if (options->xmlOutput) { printf_xml(" "); - i2a_ASN1_OBJECT(fileBIO, X509_get0_tbs_sigalg(x509Cert)); + X509_signature_print(fileBIO, X509_get0_tbs_sigalg(x509Cert), NULL); printf_xml("\n"); } } @@ -2680,7 +2677,7 @@ int showCertificate(struct sslCheckOptions *options) if (!(X509_FLAG_COMPAT & X509_FLAG_NO_PUBKEY)) { printf(" Public Key Algorithm: "); - ASN1_OBJECT *xpoid; + ASN1_OBJECT *xpoid = NULL; i2a_ASN1_OBJECT(stdoutBIO, xpoid); printf("\n"); if (options->xmlOutput) @@ -3193,9 +3190,6 @@ int testHost(struct sslCheckOptions *options) populateCipherList(options, TLSv1_client_method()); #ifndef OPENSSL_NO_SSL3 populateCipherList(options, SSLv3_client_method()); -#endif -#ifndef OPENSSL_NO_SSL2 - populateCipherList(options, SSLv2_client_method()); #endif break; case tls_all: @@ -3224,11 +3218,6 @@ int testHost(struct sslCheckOptions *options) case ssl_v3: populateCipherList(options, SSLv3_client_method()); break; -#endif -#ifndef OPENSSL_NO_SSL2 - case ssl_v2: - populateCipherList(options, SSLv2_client_method()); - break; #endif } printf("\n %sSupported Client Cipher(s):%s\n", COL_BLUE, RESET); @@ -3327,16 +3316,7 @@ int testHost(struct sslCheckOptions *options) if (status != false) status = testProtocolCiphers(options, SSLv3_client_method()); #endif -#ifndef OPENSSL_NO_SSL2 - if (status != false) - status = testProtocolCiphers(options, SSLv2_client_method()); -#endif - break; -#ifndef OPENSSL_NO_SSL2 - case ssl_v2: - status = testProtocolCiphers(options, SSLv2_client_method()); break; -#endif #ifndef OPENSSL_NO_SSL3 case ssl_v3: status = testProtocolCiphers(options, SSLv3_client_method()); @@ -3393,10 +3373,6 @@ int testHost(struct sslCheckOptions *options) #ifndef OPENSSL_NO_SSL3 if (status != false) status = checkCertificateProtocol(options, SSLv3_client_method()); -#endif -#ifndef OPENSSL_NO_SSL2 - if (status != false) - status = checkCertificateProtocol(options, SSLv2_client_method()); #endif } diff --git a/sslscan.h b/sslscan.h index bb48636..7df1316 100644 --- a/sslscan.h +++ b/sslscan.h @@ -105,7 +105,7 @@ struct sslCipher { // Cipher Properties... const char *name; - char *version; + const char *version; int bits; char description[512]; const SSL_METHOD *sslMethod; From 06e9329bb3618016376d97c237bd36a353f35a24 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Wed, 27 Nov 2019 01:14:40 -0500 Subject: [PATCH 09/52] Now detects number of processors and makes static builds in parallel. --- Makefile | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 9774976..a3880e1 100644 --- a/Makefile +++ b/Makefile @@ -72,6 +72,14 @@ LDFLAGS += -L/usr/local/lib -L/usr/local/ssl/lib -L/usr/local/opt/openssl/lib CFLAGS += -I/usr/local/include -I/usr/local/ssl/include -I/usr/local/ssl/include/openssl -I/usr/local/opt/openssl/include -I/opt/local/include -I/opt/local/include/openssl endif +# Find the number of processors on the system (used in -j option in building OpenSSL). +# Uses /usr/bin/nproc if available, otherwise defaults to 1. +NUM_PROCS = 1 +ifneq (,$(wildcard /usr/bin/nproc)) + NUM_PROCS = `/usr/bin/nproc --all` +endif + + .PHONY: all sslscan clean install uninstall static opensslpull all: sslscan @@ -127,12 +135,12 @@ openssl/Makefile: .openssl.is.fresh endif openssl/libcrypto.a: openssl/Makefile - $(MAKE) -C openssl depend - $(MAKE) -C openssl all -# $(MAKE) -C openssl test # Disabled because this takes 45+ minutes for OpenSSL v1.1.1. + $(MAKE) -j $(NUM_PROCS) -C openssl depend + $(MAKE) -j $(NUM_PROCS) -C openssl all +# $(MAKE) -j $(NUM_PROCS) -C openssl test # Disabled because this takes 45+ minutes for OpenSSL v1.1.1. static: openssl/libcrypto.a - $(MAKE) sslscan STATIC_BUILD=TRUE + $(MAKE) -j $(NUM_PROCS) sslscan STATIC_BUILD=TRUE clean: if [ -d openssl ]; then ( rm -rf openssl ); fi; From 4f69614dc6eefaf42c6283e3bce28a6828fd26f7 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Wed, 27 Nov 2019 01:26:27 -0500 Subject: [PATCH 10/52] Added manual tests for SSLv2 and SSLv3. --- sslscan.c | 283 ++++++++++++++++++++++++++++++++++++++++++++---------- sslscan.h | 2 + 2 files changed, 232 insertions(+), 53 deletions(-) diff --git a/sslscan.c b/sslscan.c index aabcb6c..9fb39aa 100644 --- a/sslscan.c +++ b/sslscan.c @@ -1299,10 +1299,6 @@ int testRenegotiation(struct sslCheckOptions *options, const SSL_METHOD *sslMeth const char* printableSslMethod(const SSL_METHOD *sslMethod) { -#ifndef OPENSSL_NO_SSL3 - if (sslMethod == SSLv3_client_method()) - return "SSLv3"; -#endif if (sslMethod == TLSv1_client_method()) return "TLSv1.0"; #if OPENSSL_VERSION_NUMBER >= 0x10001000L @@ -3188,9 +3184,6 @@ int testHost(struct sslCheckOptions *options) populateCipherList(options, TLSv1_1_client_method()); #endif populateCipherList(options, TLSv1_client_method()); -#ifndef OPENSSL_NO_SSL3 - populateCipherList(options, SSLv3_client_method()); -#endif break; case tls_all: populateCipherList(options, TLSv1_3_client_method()); @@ -3214,11 +3207,6 @@ int testHost(struct sslCheckOptions *options) case tls_v10: populateCipherList(options, TLSv1_client_method()); break; -#ifndef OPENSSL_NO_SSL3 - case ssl_v3: - populateCipherList(options, SSLv3_client_method()); - break; -#endif } printf("\n %sSupported Client Cipher(s):%s\n", COL_BLUE, RESET); sslCipherPointer = options->ciphers; @@ -3294,6 +3282,29 @@ int testHost(struct sslCheckOptions *options) #endif } + printf(" %sSSL Protocols:%s\n", COL_BLUE, RESET); + // Check if SSLv2 is enabled. + if ((options->sslVersion == ssl_all) || (options->sslVersion == ssl_v2)) { + if (runSSLv2Test(options)) { + printf("SSLv2 is %senabled%s\n", COL_RED, RESET); + printf_xml(" \n"); + } else { + printf("SSLv2 is %snot enabled%s\n", COL_GREEN, RESET); + printf_xml(" \n"); + } + } + + // Check if SSLv3 is enabled. + if ((options->sslVersion == ssl_all) || (options->sslVersion == ssl_v3)) { + if (runSSLv3Test(options)) { + printf("SSLv3 is %senabled%s\n", COL_RED, RESET); + printf_xml(" \n"); + } else { + printf("SSLv3 is %snot enabled%s\n", COL_GREEN, RESET); + printf_xml(" \n"); + } + } + printf("\n"); if (options->ciphersuites) { @@ -3312,16 +3323,7 @@ int testHost(struct sslCheckOptions *options) #endif if (status != false) status = testProtocolCiphers(options, TLSv1_client_method()); -#ifndef OPENSSL_NO_SSL3 - if (status != false) - status = testProtocolCiphers(options, SSLv3_client_method()); -#endif break; -#ifndef OPENSSL_NO_SSL3 - case ssl_v3: - status = testProtocolCiphers(options, SSLv3_client_method()); - break; -#endif case tls_all: if (status != false) status = testProtocolCiphers(options, TLSv1_3_client_method()); @@ -3370,10 +3372,6 @@ int testHost(struct sslCheckOptions *options) #endif if (status != false) status = checkCertificateProtocol(options, TLSv1_client_method()); -#ifndef OPENSSL_NO_SSL3 - if (status != false) - status = checkCertificateProtocol(options, SSLv3_client_method()); -#endif } // Print client auth trusted CAs @@ -3617,16 +3615,14 @@ int main(int argc, char *argv[]) else if (strcmp("--starttls-psql", argv[argLoop]) == 0) options.starttls_psql = true; -#ifndef OPENSSL_NO_SSL2 // SSL v2 only... else if (strcmp("--ssl2", argv[argLoop]) == 0) options.sslVersion = ssl_v2; -#endif -#ifndef OPENSSL_NO_SSL3 + // SSL v3 only... else if (strcmp("--ssl3", argv[argLoop]) == 0) options.sslVersion = ssl_v3; -#endif + // TLS v1 only... else if (strcmp("--tls10", argv[argLoop]) == 0) options.sslVersion = tls_v10; @@ -3819,14 +3815,6 @@ int main(int argc, char *argv[]) case mode_version: printf("%s\t\t%s\n\t\t%s\n%s", COL_BLUE, VERSION, SSLeay_version(SSLEAY_VERSION), RESET); -#ifdef OPENSSL_NO_SSL2 - printf("\t\t%sOpenSSL version does not support SSLv2%s\n", COL_RED, RESET); - printf("\t\t%sSSLv2 ciphers will not be detected%s\n", COL_RED, RESET); -#endif -#ifdef OPENSSL_NO_SSL3 - printf("\t\t%sOpenSSL version does not support SSLv3%s\n", COL_RED, RESET); - printf("\t\t%sSSLv3 ciphers will not be detected%s\n", COL_RED, RESET); -#endif #if OPENSSL_VERSION_NUMBER < 0x10001000L printf("\t\t%sOpenSSL version does not support TLSv1.1%s\n", COL_RED, RESET); printf("\t\t%sTLSv1.1 ciphers will not be detected%s\n", COL_RED, RESET); @@ -3843,10 +3831,6 @@ int main(int argc, char *argv[]) #ifdef OPENSSL_NO_SSL2 printf("%sOpenSSL version does not support SSLv2%s\n", COL_RED, RESET); printf("%sSSLv2 ciphers will not be detected%s\n\n", COL_RED, RESET); -#endif -#ifdef OPENSSL_NO_SSL3 - printf("%sOpenSSL version does not support SSLv3%s\n", COL_RED, RESET); - printf("%sSSLv3 ciphers will not be detected%s\n", COL_RED, RESET); #endif printf("%sCommand:%s\n", COL_BLUE, RESET); printf(" %s%s [Options] [host:port | host]%s\n\n", COL_GREEN, argv[0], RESET); @@ -3862,12 +3846,8 @@ int main(int argc, char *argv[]) printf(" %s--show-ciphers%s Show supported client ciphers\n", COL_GREEN, RESET); printf(" %s--show-cipher-ids%s Show cipher ids\n", COL_GREEN, RESET); printf(" %s--show-times%s Show handhake times in milliseconds\n", COL_GREEN, RESET); -#ifndef OPENSSL_NO_SSL2 printf(" %s--ssl2%s Only check SSLv2 ciphers\n", COL_GREEN, RESET); -#endif -#ifndef OPENSSL_NO_SSL3 printf(" %s--ssl3%s Only check SSLv3 ciphers\n", COL_GREEN, RESET); -#endif printf(" %s--tls10%s Only check TLSv1.0 ciphers\n", COL_GREEN, RESET); #if OPENSSL_VERSION_NUMBER >= 0x10001000L printf(" %s--tls11%s Only check TLSv1.1 ciphers\n", COL_GREEN, RESET); @@ -3921,14 +3901,6 @@ int main(int argc, char *argv[]) case mode_multiple: printf("Version: %s%s%s\n%s\n%s\n", COL_GREEN, VERSION, RESET, SSLeay_version(SSLEAY_VERSION), RESET); -#ifdef OPENSSL_NO_SSL2 - printf("%sOpenSSL version does not support SSLv2%s\n", COL_RED, RESET); - printf("%sSSLv2 ciphers will not be detected%s\n\n", COL_RED, RESET); -#endif -#ifdef OPENSSL_NO_SSL3 - printf("%sOpenSSL version does not support SSLv3%s\n", COL_RED, RESET); - printf("%sSSLv3 ciphers will not be detected%s\n", COL_RED, RESET); -#endif #if OPENSSL_VERSION_NUMBER < 0x10001000L printf("\t\t%sOpenSSL version does not support TLSv1.1%s\n", COL_RED, RESET); printf("\t\t%sTLSv1.1 ciphers will not be detected%s\n", COL_RED, RESET); @@ -4027,6 +3999,211 @@ int main(int argc, char *argv[]) return 0; } +int runSSLv2Test(struct sslCheckOptions *options) { + int ret = false, s = 0; + char sslv2_client_hello[] = { + 0x80, + 0x34, /* Length: 52 */ + 0x01, /* Handshake Message Type: Client Hello */ + 0x00, 0x02, /* Version: SSL 2.0 */ + 0x00, 0x1b, /* Cipher Spec Length: 27 */ + 0x00, 0x00, /* Session ID Length: 0 */ + 0x00, 0x10, /* Challenge Length: 16 */ + 0x05, 0x00, 0x80, /* SSL2_IDEA_128_CBC_WITH_MD5 */ + 0x03, 0x00, 0x80, /* SSL2_RC2_128_CBC_WITH_MD5 */ + 0x01, 0x00, 0x80, /* SSL2_RC4_128_WITH_MD5 */ + 0x07, 0x00, 0xc0, /* SSL2_DES_192_EDE3_CBC_WITH_MD5 */ + 0x08, 0x00, 0x80, /* SSL2_RC4_64_WITH_MD5 */ + 0x06, 0x00, 0x40, /* SSL2_DES_64_CBC_WITH_MD5 */ + 0x04, 0x00, 0x80, /* SSL2_RC2_128_CBC_EXPORT40_WITH_MD5 */ + 0x02, 0x00, 0x80, /* SSL2_RC4_128_EXPORT40_WITH_MD5 */ + 0x00, 0x00, 0x00, /* TLS_NULL_WITH_NULL_NULL */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f /* Challenge */ + }; + char response[8] = {0}; + + /* Create a socket to the target. */ + s = tcpConnect(options); + + /* If a connection could not be made, return false. */ + if (s == 0) + return false; + + /* Send the SSLv2 Client Hello packet. */ + if (send(s, sslv2_client_hello, sizeof(sslv2_client_hello), 0) <= 0) { + printf_error("send() failed: %s\n", strerror(errno)); + exit(1); + } + + /* Read a small amount of the response. */ + if (recv(s, response, sizeof(response), 0) != sizeof(response)) + goto done; /* Returns false. */ + + /* If the Handshake Message Type is Server Hello (0x04) and the Version is SSL 2.0 + * (0x00, 0x02), we confirm that this is SSL v2.*/ + if ((response[2] == 0x04) && (response[5] == 0x00) && (response[6] == 0x02)) + ret = true; + + done: + close(s); + return ret; +} + +int runSSLv3Test(struct sslCheckOptions *options) { + int ret = false, s = 0; + uint32_t timestamp = htonl(time(NULL)); /* Current time stamp. */ + char sslv3_client_hello_1[] = { + 0x16, /* Content Type: Handshake (22) */ + 0x03, 0x00, /* Version SSL 3.0 */ + 0x00, 0xe8, /* Length: 232 */ + 0x01, /* Handshake Type: Client Hello */ + 0x00, 0x00, 0xe4, /* Length: 228 */ + 0x03, 0x00, /* Version: SSL 3.0 */ + }; + + char sslv3_client_hello_2[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, /* Random bytes */ + 0x00, /* Session ID Length */ + 0x00, 0xbc, /* Cipher Suites Length: 188 */ + 0xc0, 0x14, /* TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA */ + 0xc0, 0x0a, /* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA */ + 0x00, 0x39, /* TLS_DHE_RSA_WITH_AES_256_CBC_SHA */ + 0x00, 0x38, /* TLS_DHE_DSS_WITH_AES_256_CBC_SHA */ + 0x00, 0x37, /* TLS_DH_RSA_WITH_AES_256_CBC_SHA */ + 0x00, 0x36, /* TLS_DH_DSS_WITH_AES_256_CBC_SHA */ + 0x00, 0x88, /* TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA */ + 0x00, 0x87, /* TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA */ + 0x00, 0x86, /* TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA */ + 0x00, 0x85, /* TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA */ + 0xc0, 0x19, /* TLS_ECDH_anon_WITH_AES_256_CBC_SHA */ + 0x00, 0x3a, /* TLS_DH_anon_WITH_AES_256_CBC_SHA */ + 0x00, 0x89, /* TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA */ + 0xc0, 0x0f, /* TLS_ECDH_RSA_WITH_AES_256_CBC_SHA */ + 0xc0, 0x05, /* TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA */ + 0x00, 0x35, /* TLS_RSA_WITH_AES_256_CBC_SHA */ + 0x00, 0x84, /* TLS_RSA_WITH_CAMELLIA_256_CBC_SHA */ + 0x00, 0x95, /* TLS_RSA_PSK_WITH_AES_256_CBC_SHA */ + 0xc0, 0x13, /* TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA */ + 0xc0, 0x09, /* TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA */ + 0x00, 0x33, /* TLS_DHE_RSA_WITH_AES_128_CBC_SHA */ + 0x00, 0x32, /* TLS_DHE_DSS_WITH_AES_128_CBC_SHA */ + 0x00, 0x31, /* TLS_DH_RSA_WITH_AES_128_CBC_SHA */ + 0x00, 0x30, /* TLS_DH_DSS_WITH_AES_128_CBC_SHA */ + 0x00, 0x9a, /* TLS_DHE_RSA_WITH_SEED_CBC_SHA */ + 0x00, 0x99, /* TLS_DHE_DSS_WITH_SEED_CBC_SHA */ + 0x00, 0x98, /* TLS_DH_RSA_WITH_SEED_CBC_SHA */ + 0x00, 0x97, /* TLS_DH_DSS_WITH_SEED_CBC_SHA */ + 0x00, 0x45, /* TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA */ + 0x00, 0x44, /* TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA */ + 0x00, 0x43, /* TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA */ + 0x00, 0x42, /* TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA */ + 0xc0, 0x18, /* TLS_ECDH_anon_WITH_AES_128_CBC_SHA */ + 0x00, 0x34, /* TLS_DH_anon_WITH_AES_128_CBC_SHA */ + 0x00, 0x9b, /* TLS_DH_anon_WITH_SEED_CBC_SHA */ + 0x00, 0x46, /* TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA */ + 0xc0, 0x0e, /* TLS_ECDH_RSA_WITH_AES_128_CBC_SHA */ + 0xc0, 0x04, /* TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA */ + 0x00, 0x2f, /* TLS_RSA_WITH_AES_128_CBC_SHA */ + 0x00, 0x96, /* TLS_RSA_WITH_SEED_CBC_SHA */ + 0x00, 0x41, /* TLS_RSA_WITH_CAMELLIA_128_CBC_SHA */ + 0x00, 0x07, /* TLS_RSA_WITH_IDEA_CBC_SHA */ + 0x00, 0x94, /* TLS_RSA_PSK_WITH_AES_128_CBC_SHA */ + 0xc0, 0x11, /* TLS_ECDHE_RSA_WITH_RC4_128_SHA */ + 0xc0, 0x07, /* TLS_ECDHE_ECDSA_WITH_RC4_128_SHA */ + 0x00, 0x66, /* TLS_DHE_DSS_WITH_RC4_128_SHA */ + 0xc0, 0x16, /* TLS_ECDH_anon_WITH_RC4_128_SHA */ + 0x00, 0x18, /* TLS_DH_anon_WITH_RC4_128_MD5 */ + 0xc0, 0x0c, /* TLS_ECDH_RSA_WITH_RC4_128_SHA */ + 0xc0, 0x02, /* TLS_ECDH_ECDSA_WITH_RC4_128_SHA */ + 0x00, 0x05, /* TLS_RSA_WITH_RC4_128_SHA */ + 0x00, 0x04, /* TLS_RSA_WITH_RC4_128_MD5 */ + 0x00, 0x92, /* TLS_RSA_PSK_WITH_RC4_128_SHA */ + 0xc0, 0x12, /* TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA */ + 0xc0, 0x08, /* TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA */ + 0x00, 0x16, /* TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA */ + 0x00, 0x13, /* TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA */ + 0x00, 0x10, /* TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA */ + 0x00, 0x0d, /* TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA */ + 0xc0, 0x17, /* TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA */ + 0x00, 0x1b, /* TLS_DH_anon_WITH_3DES_EDE_CBC_SHA */ + 0xc0, 0x0d, /* TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA */ + 0xc0, 0x03, /* TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA */ + 0x00, 0x0a, /* TLS_RSA_WITH_3DES_EDE_CBC_SHA */ + 0x00, 0x93, /* TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA */ + 0x00, 0x63, /* TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA */ + 0x00, 0x15, /* TLS_DHE_RSA_WITH_DES_CBC_SHA */ + 0x00, 0x12, /* TLS_DHE_DSS_WITH_DES_CBC_SHA */ + 0x00, 0x0f, /* TLS_DH_RSA_WITH_DES_CBC_SHA */ + 0x00, 0x0c, /* TLS_DH_DSS_WITH_DES_CBC_SHA */ + 0x00, 0x1a, /* TLS_DH_anon_WITH_DES_CBC_SHA */ + 0x00, 0x62, /* TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA */ + 0x00, 0x09, /* TLS_RSA_WITH_DES_CBC_SHA */ + 0x00, 0x61, /* TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 */ + 0x00, 0x65, /* TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA */ + 0x00, 0x64, /* TLS_RSA_EXPORT1024_WITH_RC4_56_SHA */ + 0x00, 0x60, /* TLS_RSA_EXPORT1024_WITH_RC4_56_MD5 */ + 0x00, 0x14, /* TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA */ + 0x00, 0x11, /* TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA */ + 0x00, 0x0e, /* TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA */ + 0x00, 0x0b, /* TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA */ + 0x00, 0x19, /* TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA */ + 0x00, 0x08, /* TLS_RSA_EXPORT_WITH_DES40_CBC_SHA */ + 0x00, 0x06, /* TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 */ + 0x00, 0x17, /* TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 */ + 0x00, 0x03, /* TLS_RSA_EXPORT_WITH_RC4_40_MD5 */ + 0xc0, 0x10, /* TLS_ECDHE_RSA_WITH_NULL_SHA */ + 0xc0, 0x06, /* TLS_ECDHE_ECDSA_WITH_NULL_SHA */ + 0xc0, 0x15, /* TLS_ECDH_anon_WITH_NULL_SHA */ + 0xc0, 0x0b, /* TLS_ECDH_RSA_WITH_NULL_SHA */ + 0xc0, 0x01, /* TLS_ECDH_ECDSA_WITH_NULL_SHA */ + 0x00, 0x02, /* TLS_RSA_WITH_NULL_SHA */ + 0x00, 0x01, /* TLS_RSA_WITH_NULL_MD5 */ + 0x00, 0xff, /* TLS_EMPTY_RENEGOTIATION_INFO_SCSV */ + 0x02, /* Compression Methods Length: 2 */ + 0x01, 0x00, /* DEFLATE, none */ + }; + char response[16] = {0}; + + /* Create a socket to the target. */ + s = tcpConnect(options); + + /* If a connection could not be made, return false. */ + if (s == 0) + return false; + + /* Send the SSLv3 Client Hello packet. */ + if (send(s, sslv3_client_hello_1, sizeof(sslv3_client_hello_1), 0) <= 0) { + printf_error("send() failed: %s\n", strerror(errno)); + exit(1); + } + + if (send(s, ×tamp, sizeof(timestamp), 0) <= 0) { + printf_error("send() failed: %s\n", strerror(errno)); + exit(1); + } + + if (send(s, sslv3_client_hello_2, sizeof(sslv3_client_hello_2), 0) <= 0) { + printf_error("send() failed: %s\n", strerror(errno)); + exit(1); + } + + /* Read a small amount of the response. */ + if (recv(s, response, sizeof(response), 0) != sizeof(response)) + goto done; /* Returns false. */ + + /* If the Handshake Message Type is Server Hello (0x04) and the Version is SSL 3.0 + * (0x00, 0x02), we confirm that this is SSL v2.*/ + if ((response[0] == 0x16) && /* Content Type is Handshake (22) */ + (response[1] == 0x03) && (response[2] == 0x00) && /* Version is SSL 3.0 */ + (response[5] == 0x02) && /* Handshake Type is Server Hello (2) */ + (response[9] == 0x03) && (response[10] == 0x00)) /* Version is SSL 3.0 (again) */ + ret = true; + + done: + close(s); + return ret; +} + /* MinGW doesn't have a memmem() implementation. */ #ifdef _WIN32 diff --git a/sslscan.h b/sslscan.h index 7df1316..9ab80d3 100644 --- a/sslscan.h +++ b/sslscan.h @@ -223,6 +223,8 @@ int checkCertificateProtocols(struct sslCheckOptions *, const SSL_METHOD *); int checkCertificate(struct sslCheckOptions *, const SSL_METHOD *); int showCertificate(struct sslCheckOptions *); +int runSSLv2Test(struct sslCheckOptions *options); +int runSSLv3Test(struct sslCheckOptions *options); #endif /* vim :set ts=4 sw=4 sts=4 et : */ From 687b81eb7bbb42d49591d668ec12e0a04b8a826a Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Wed, 27 Nov 2019 10:31:08 -0500 Subject: [PATCH 11/52] Fixed typos in comments. --- sslscan.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sslscan.c b/sslscan.c index 9fb39aa..f666129 100644 --- a/sslscan.c +++ b/sslscan.c @@ -4040,7 +4040,7 @@ int runSSLv2Test(struct sslCheckOptions *options) { goto done; /* Returns false. */ /* If the Handshake Message Type is Server Hello (0x04) and the Version is SSL 2.0 - * (0x00, 0x02), we confirm that this is SSL v2.*/ + * (0x00, 0x02), we confirm that this is SSL v2. */ if ((response[2] == 0x04) && (response[5] == 0x00) && (response[6] == 0x02)) ret = true; @@ -4191,8 +4191,7 @@ int runSSLv3Test(struct sslCheckOptions *options) { if (recv(s, response, sizeof(response), 0) != sizeof(response)) goto done; /* Returns false. */ - /* If the Handshake Message Type is Server Hello (0x04) and the Version is SSL 3.0 - * (0x00, 0x02), we confirm that this is SSL v2.*/ + /* Examine response. */ if ((response[0] == 0x16) && /* Content Type is Handshake (22) */ (response[1] == 0x03) && (response[2] == 0x00) && /* Version is SSL 3.0 */ (response[5] == 0x02) && /* Handshake Type is Server Hello (2) */ From e9d8dee15112bcede801f05ffd34a47250ff1b38 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Wed, 27 Nov 2019 10:40:49 -0500 Subject: [PATCH 12/52] Added OpenSSL v1.1.1 dependency check. --- sslscan.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sslscan.c b/sslscan.c index f666129..c7df301 100644 --- a/sslscan.c +++ b/sslscan.c @@ -117,6 +117,10 @@ #include "sslscan.h" +#if OPENSSL_VERSION_NUMBER < 0x1010100fL +#error "OpenSSL v1.1.1 or later is required!" +#endif + /* Borrowed from tortls.c to dance with OpenSSL on many platforms, with * many versions and releases of OpenSSL. */ /** Does the run-time openssl version look like we need From 224b59e0f4aaada1f57afa8831df97c9fecd7edb Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Wed, 27 Nov 2019 11:26:18 -0500 Subject: [PATCH 13/52] Fixed MinGW compile warnings. --- sslscan.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/sslscan.c b/sslscan.c index c7df301..9c08aa0 100644 --- a/sslscan.c +++ b/sslscan.c @@ -81,6 +81,9 @@ #include "win32bit-compat.h" #endif #endif + + const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); + #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 #endif @@ -88,10 +91,10 @@ #include #include #include - #include #endif #include #include +#include #include #include #include @@ -4055,7 +4058,8 @@ int runSSLv2Test(struct sslCheckOptions *options) { int runSSLv3Test(struct sslCheckOptions *options) { int ret = false, s = 0; - uint32_t timestamp = htonl(time(NULL)); /* Current time stamp. */ + uint32_t timestamp = 0; + unsigned char timestamp_bytes[4] = {0}; char sslv3_client_hello_1[] = { 0x16, /* Content Type: Handshake (22) */ 0x03, 0x00, /* Version SSL 3.0 */ @@ -4181,7 +4185,13 @@ int runSSLv3Test(struct sslCheckOptions *options) { exit(1); } - if (send(s, ×tamp, sizeof(timestamp), 0) <= 0) { + timestamp = htonl(time(NULL)); /* Current time stamp. */ + timestamp_bytes[0] = timestamp & 0xff; + timestamp_bytes[1] = (timestamp >> 8) & 0xff; + timestamp_bytes[2] = (timestamp >> 16) & 0xff; + timestamp_bytes[3] = (timestamp >> 24) & 0xff; + + if (send(s, timestamp_bytes, sizeof(timestamp_bytes), 0) <= 0) { printf_error("send() failed: %s\n", strerror(errno)); exit(1); } From 2fc3ae22074bb3820e61b0afb251f7a7a3707c93 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Thu, 28 Nov 2019 11:42:13 -0500 Subject: [PATCH 14/52] Certificate info is now printed for TLS v1.3-only servers. --- sslscan.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sslscan.c b/sslscan.c index 9c08aa0..04771fd 100644 --- a/sslscan.c +++ b/sslscan.c @@ -3369,14 +3369,12 @@ int testHost(struct sslCheckOptions *options) // Show weak certificate signing algorithm or key strength if (status == true && options->checkCertificate == true) { -#if OPENSSL_VERSION_NUMBER >= 0x10001000L if (status != false) - { + status = checkCertificateProtocol(options, TLSv1_3_client_method()); + if (status != false) status = checkCertificateProtocol(options, TLSv1_2_client_method()); - } if (status != false) status = checkCertificateProtocol(options, TLSv1_1_client_method()); -#endif if (status != false) status = checkCertificateProtocol(options, TLSv1_client_method()); } From ef5ce62751e3712e7b68cb281ad5d6900ba20e8c Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Thu, 28 Nov 2019 19:27:31 -0500 Subject: [PATCH 15/52] Better organized the TLSv1.3-specific ciphersuite list. --- sslscan.c | 11 +++++------ sslscan.h | 3 +++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/sslscan.c b/sslscan.c index 04771fd..ecb966a 100644 --- a/sslscan.c +++ b/sslscan.c @@ -1618,7 +1618,7 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) printf_xml(" cipherstring, "ALL:eNULL") && strcmp(options->cipherstring, "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256")) + if (strcmp(options->cipherstring, "ALL:eNULL") && strcmp(options->cipherstring, TLSV13_CIPHERSUITES)) { printf_xml("accepted\""); printf("Accepted "); @@ -3115,11 +3115,10 @@ int testProtocolCiphers(struct sslCheckOptions *options, const SSL_METHOD *sslMe int status; status = true; - //strncpy(options->cipherstring, "", 1); - if(sslMethod==TLSv1_3_client_method()) - strncpy(options->cipherstring, "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256", 122); + if (sslMethod == TLSv1_3_client_method()) + strncpy(options->cipherstring, TLSV13_CIPHERSUITES, sizeof(options->cipherstring)); else - strncpy(options->cipherstring, "ALL:eNULL", 10); + strncpy(options->cipherstring, "ALL:eNULL", sizeof(options->cipherstring)); // Loop until the server won't accept any more ciphers while (status == true) @@ -3135,7 +3134,7 @@ int testProtocolCiphers(struct sslCheckOptions *options, const SSL_METHOD *sslMe SSL_CTX_set_options(options->ctx, 0); // minimal protocol version - if(sslMethod==TLSv1_3_client_method()) + if (sslMethod == TLSv1_3_client_method()) SSL_CTX_set_min_proto_version(options->ctx, TLS1_3_VERSION); // Load Certs if required... diff --git a/sslscan.h b/sslscan.h index 9ab80d3..0978fa6 100644 --- a/sslscan.h +++ b/sslscan.h @@ -57,6 +57,9 @@ #define tls_v12 6 #define tls_v13 7 +/* We must maintain our own list of TLSv1.3-specific ciphersuites here, because SSL_CTX_get_ciphers() will *always* return TLSv1.2 ciphersuites, even when SSL_CTX_set_min_proto_version() and SSL_CTX_set_max_proto_version() are used. This is confirmed by an OpenSSL developer here: https://github.com/openssl/openssl/issues/7196#issuecomment-420575202 */ +#define TLSV13_CIPHERSUITES "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256" + // Macros for various outputs #define printf(format, ...) if (!xml_to_stdout) fprintf(stdout, format, ##__VA_ARGS__) #define printf_error(format, ...) fprintf(stderr, format, ##__VA_ARGS__) From 712be3c9c59732a548e03ecf24797dbe046d4c42 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Thu, 28 Nov 2019 21:54:15 -0500 Subject: [PATCH 16/52] Fixed SCSV fallback test under OpenSSL v1.1.1. --- sslscan.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/sslscan.c b/sslscan.c index ecb966a..be231d6 100644 --- a/sslscan.c +++ b/sslscan.c @@ -1013,7 +1013,7 @@ int testFallback(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) // Connect SSL over socket connStatus = SSL_connect(ssl); - if (connStatus) + if (connStatus > 0) { if (!downgraded) { @@ -1022,26 +1022,24 @@ int testFallback(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) { secondMethod = TLSv1_2_client_method(); } -#if OPENSSL_VERSION_NUMBER >= 0x10001000L - if (sslversion == TLS1_2_VERSION) - { - secondMethod = TLSv1_1_client_method(); - } else -#endif - if (sslversion == TLS1_VERSION) - { - secondMethod = TLSv1_client_method(); - } - else if (sslversion == TLS1_VERSION) + else if (sslversion == TLS1_2_VERSION) { - printf("Server only supports TLSv1.0"); - status = false; - } - else - { - printf("Server doesn't support TLS - skipping TLS Fallback SCSV check\n\n"); - status = false; + secondMethod = TLSv1_1_client_method(); } + else if (sslversion == TLS1_VERSION) + { + secondMethod = TLSv1_client_method(); + } + else if (sslversion == TLS1_VERSION) + { + printf("Server only supports TLSv1.0"); + status = false; + } + else + { + printf("Server doesn't support TLS - skipping TLS Fallback SCSV check\n\n"); + status = false; + } } else { From 2016860bfe2462a9e06830b61b60f9897d08d947 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Thu, 28 Nov 2019 22:22:31 -0500 Subject: [PATCH 17/52] Added detection of X25519 and X448 key exchanges. --- sslscan.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sslscan.c b/sslscan.c index be231d6..88b2c8f 100644 --- a/sslscan.c +++ b/sslscan.c @@ -1484,7 +1484,6 @@ int ssl_print_tmp_key(struct sslCheckOptions *options, SSL *s) } printf_xml(" dhebits=\"%d\"", EVP_PKEY_bits(key)); break; -#ifndef OPENSSL_NO_EC case EVP_PKEY_EC: { EC_KEY *ec = EVP_PKEY_get1_EC_KEY(key); @@ -1498,7 +1497,14 @@ int ssl_print_tmp_key(struct sslCheckOptions *options, SSL *s) printf(" Curve %s DHE %d", cname, EVP_PKEY_bits(key)); printf_xml(" curve=\"%s\" ecdhebits=\"%d\"", cname, EVP_PKEY_bits(key)); } -#endif + case EVP_PKEY_X25519: + printf(" %sX25519%s", COL_GREEN, RESET); + break; + case EVP_PKEY_X448: + printf(" %sX448%s", COL_GREEN, RESET); + break; + default: + printf(" %sUnknown ID (%d)%s", COL_YELLOW, EVP_PKEY_id(key), RESET); } EVP_PKEY_free(key); return 1; From d6331ba36cdf5b60b9364918e2e51d3c7425c82c Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Thu, 28 Nov 2019 23:33:21 -0500 Subject: [PATCH 18/52] Fixed bug when parsing ECC key exchanges. --- sslscan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sslscan.c b/sslscan.c index 88b2c8f..bc90efc 100644 --- a/sslscan.c +++ b/sslscan.c @@ -1497,6 +1497,7 @@ int ssl_print_tmp_key(struct sslCheckOptions *options, SSL *s) printf(" Curve %s DHE %d", cname, EVP_PKEY_bits(key)); printf_xml(" curve=\"%s\" ecdhebits=\"%d\"", cname, EVP_PKEY_bits(key)); } + break; case EVP_PKEY_X25519: printf(" %sX25519%s", COL_GREEN, RESET); break; From 852bc747b308b899dc27aa1886c3be642d8a9991 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Sat, 30 Nov 2019 23:08:42 -0500 Subject: [PATCH 19/52] Replaced occurances of cipher list 'ALL:COMPLEMENTOFALL' with a define. Explicitly added RC4-MD5 to cipher list. --- sslscan.c | 20 ++++++++++---------- sslscan.h | 3 +++ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/sslscan.c b/sslscan.c index bc90efc..5bfdfac 100644 --- a/sslscan.c +++ b/sslscan.c @@ -166,7 +166,7 @@ int populateCipherList(struct sslCheckOptions *options, const SSL_METHOD *sslMet printf_error("%sERROR: Could not create CTX object.%s\n", COL_RED, RESET); return false; } - SSL_CTX_set_cipher_list(options->ctx, "ALL:COMPLEMENTOFALL"); + SSL_CTX_set_cipher_list(options->ctx, CIPHERSUITE_LIST_ALL); ssl = SSL_new(options->ctx); if (ssl == NULL) { printf_error("%sERROR: Could not create SSL object.%s\n", COL_RED, RESET); @@ -835,7 +835,7 @@ int testCompression(struct sslCheckOptions *options, const SSL_METHOD *sslMethod tls_reneg_init(options); if (options->ctx != NULL) { - if (SSL_CTX_set_cipher_list(options->ctx, "ALL:COMPLEMENTOFALL") != 0) + if (SSL_CTX_set_cipher_list(options->ctx, CIPHERSUITE_LIST_ALL) != 0) { // Load Certs if required... @@ -975,7 +975,7 @@ int testFallback(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) { SSL_CTX_set_mode(options->ctx, SSL_MODE_SEND_FALLBACK_SCSV); } - if (SSL_CTX_set_cipher_list(options->ctx, "ALL:COMPLEMENTOFALL") != 0) + if (SSL_CTX_set_cipher_list(options->ctx, CIPHERSUITE_LIST_ALL) != 0) { // Load Certs if required... @@ -1140,7 +1140,7 @@ int testRenegotiation(struct sslCheckOptions *options, const SSL_METHOD *sslMeth tls_reneg_init(options); if (options->ctx != NULL) { - if (SSL_CTX_set_cipher_list(options->ctx, "ALL:COMPLEMENTOFALL") != 0) + if (SSL_CTX_set_cipher_list(options->ctx, CIPHERSUITE_LIST_ALL) != 0) { // Load Certs if required... @@ -1623,7 +1623,7 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) printf_xml(" cipherstring, "ALL:eNULL") && strcmp(options->cipherstring, TLSV13_CIPHERSUITES)) + if (strcmp(options->cipherstring, CIPHERSUITE_LIST_ALL) && strcmp(options->cipherstring, TLSV13_CIPHERSUITES)) { printf_xml("accepted\""); printf("Accepted "); @@ -1880,7 +1880,7 @@ int checkCertificate(struct sslCheckOptions *options, const SSL_METHOD *sslMetho if (options->ctx != NULL) { - if (SSL_CTX_set_cipher_list(options->ctx, "ALL:COMPLEMENTOFALL") != 0) + if (SSL_CTX_set_cipher_list(options->ctx, CIPHERSUITE_LIST_ALL) != 0) { // Load Certs if required... if ((options->clientCertsFile != 0) || (options->privateKeyFile != 0)) @@ -2300,7 +2300,7 @@ int ocspRequest(struct sslCheckOptions *options) if (options->ctx != NULL) { - if (SSL_CTX_set_cipher_list(options->ctx, "ALL:COMPLEMENTOFALL") != 0) + if (SSL_CTX_set_cipher_list(options->ctx, CIPHERSUITE_LIST_ALL) != 0) { // Load Certs if required... if ((options->clientCertsFile != 0) || (options->privateKeyFile != 0)) @@ -2478,7 +2478,7 @@ int showCertificate(struct sslCheckOptions *options) options->ctx = SSL_CTX_new(sslMethod); if (options->ctx != NULL) { - if (SSL_CTX_set_cipher_list(options->ctx, "ALL:COMPLEMENTOFALL") != 0) + if (SSL_CTX_set_cipher_list(options->ctx, CIPHERSUITE_LIST_ALL) != 0) { // Load Certs if required... if ((options->clientCertsFile != 0) || (options->privateKeyFile != 0)) @@ -2929,7 +2929,7 @@ int showTrustedCAs(struct sslCheckOptions *options) options->ctx = SSL_CTX_new(sslMethod); if (options->ctx != NULL) { - if (SSL_CTX_set_cipher_list(options->ctx, "ALL:COMPLEMENTOFALL") != 0) + if (SSL_CTX_set_cipher_list(options->ctx, CIPHERSUITE_LIST_ALL) != 0) { // Load Certs if required... if ((options->clientCertsFile != 0) || (options->privateKeyFile != 0)) @@ -3123,7 +3123,7 @@ int testProtocolCiphers(struct sslCheckOptions *options, const SSL_METHOD *sslMe if (sslMethod == TLSv1_3_client_method()) strncpy(options->cipherstring, TLSV13_CIPHERSUITES, sizeof(options->cipherstring)); else - strncpy(options->cipherstring, "ALL:eNULL", sizeof(options->cipherstring)); + strncpy(options->cipherstring, CIPHERSUITE_LIST_ALL, sizeof(options->cipherstring)); // Loop until the server won't accept any more ciphers while (status == true) diff --git a/sslscan.h b/sslscan.h index 0978fa6..806e39a 100644 --- a/sslscan.h +++ b/sslscan.h @@ -60,6 +60,9 @@ /* We must maintain our own list of TLSv1.3-specific ciphersuites here, because SSL_CTX_get_ciphers() will *always* return TLSv1.2 ciphersuites, even when SSL_CTX_set_min_proto_version() and SSL_CTX_set_max_proto_version() are used. This is confirmed by an OpenSSL developer here: https://github.com/openssl/openssl/issues/7196#issuecomment-420575202 */ #define TLSV13_CIPHERSUITES "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256" +/* Somehow, RC4-MD5 is silently excluded in the latest OpenSSL release unless its explicitly included. */ +#define CIPHERSUITE_LIST_ALL "ALL:COMPLEMENTOFALL:RC4-MD5:@SECLEVEL=0" + // Macros for various outputs #define printf(format, ...) if (!xml_to_stdout) fprintf(stdout, format, ##__VA_ARGS__) #define printf_error(format, ...) fprintf(stderr, format, ##__VA_ARGS__) From 2f32474ef72d2354f322640a8ec1f1d8d13df3d2 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Tue, 3 Dec 2019 18:01:12 -0500 Subject: [PATCH 20/52] Added notes about ciphersuite tests & certificate information being unavailable against SSLv2 and SSLv3. --- sslscan.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sslscan.c b/sslscan.c index 5bfdfac..2804a76 100644 --- a/sslscan.c +++ b/sslscan.c @@ -3334,6 +3334,8 @@ int testHost(struct sslCheckOptions *options) #endif if (status != false) status = testProtocolCiphers(options, TLSv1_client_method()); + if (status != false) + printf("Ciphers cannot be enumerated through SSLv2 nor SSLv3.\n\n"); break; case tls_all: if (status != false) @@ -3381,6 +3383,8 @@ int testHost(struct sslCheckOptions *options) status = checkCertificateProtocol(options, TLSv1_1_client_method()); if (status != false) status = checkCertificateProtocol(options, TLSv1_client_method()); + if (status != false) + printf("Certificate information cannot be enumerated through SSLv2 nor SSLv3.\n\n"); } // Print client auth trusted CAs From 355ac90491a0bbd50ce10d61344513728bef39d2 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Wed, 4 Dec 2019 16:00:57 -0500 Subject: [PATCH 21/52] Removed ciphersuite warning for SSLv2 and SSLv3, as it was being printed at inappropriate times. --- sslscan.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sslscan.c b/sslscan.c index 2804a76..04cebf7 100644 --- a/sslscan.c +++ b/sslscan.c @@ -3334,8 +3334,6 @@ int testHost(struct sslCheckOptions *options) #endif if (status != false) status = testProtocolCiphers(options, TLSv1_client_method()); - if (status != false) - printf("Ciphers cannot be enumerated through SSLv2 nor SSLv3.\n\n"); break; case tls_all: if (status != false) From cb131a64e1342f33a47746aaadd7df511196e729 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Thu, 5 Dec 2019 15:32:20 -0500 Subject: [PATCH 22/52] Added permissive security callback to allow processing of 512-bit DH parameters and NULL ciphers. --- Makefile | 4 ++-- sslscan.c | 52 ++++++++++++++++++++++++++++++++-------------------- sslscan.h | 5 ++++- 3 files changed, 38 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index a3880e1..0ce7602 100644 --- a/Makefile +++ b/Makefile @@ -127,11 +127,11 @@ opensslpull: # Need to build OpenSSL differently on OSX ifeq ($(OS), Darwin) openssl/Makefile: .openssl.is.fresh - cd ./openssl; ./Configure -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIC enable-weak-ssl-ciphers zlib darwin64-x86_64-cc + cd ./openssl; ./Configure -fstack-protector-all -D_FORTIFY_SOURCE=2 -DOPENSSL_TLS_SECURITY_LEVEL=0 -fPIC enable-weak-ssl-ciphers zlib darwin64-x86_64-cc # Any other *NIX platform else openssl/Makefile: .openssl.is.fresh - cd ./openssl; ./config -v -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIC no-shared enable-weak-ssl-ciphers zlib + cd ./openssl; ./config -v -fstack-protector-all -D_FORTIFY_SOURCE=2 -DOPENSSL_TLS_SECURITY_LEVEL=0 -fPIC no-shared enable-weak-ssl-ciphers zlib endif openssl/libcrypto.a: openssl/Makefile diff --git a/sslscan.c b/sslscan.c index 04cebf7..e834588 100644 --- a/sslscan.c +++ b/sslscan.c @@ -151,6 +151,18 @@ const SSL_METHOD *TLSv1_3_method(void) return TLS_method(); } +/* Callback set through SSL_set_security_callback() and SSL_CTX_set_security_callback(). Allows all weak algorithms. */ +static int security_callback_allow_all(const SSL *s, const SSL_CTX *ctx, int op, int bits, int nid, void *other, void *ex) { + return 1; +} + +/* Creates an SSL_CTX using CTX_new(), and sets the permissive security callback on it. Free with CTX_FREE(). */ +SSL_CTX *CTX_new(const SSL_METHOD *method) { + SSL_CTX *ret = SSL_CTX_new(method); + SSL_CTX_set_security_callback(ret, security_callback_allow_all); + return ret; +} + // Adds Ciphers to the Cipher List structure int populateCipherList(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) { @@ -161,7 +173,7 @@ int populateCipherList(struct sslCheckOptions *options, const SSL_METHOD *sslMet // STACK_OF is a sign that you should be using C++ :) STACK_OF(SSL_CIPHER) *cipherList; SSL *ssl = NULL; - options->ctx = SSL_CTX_new(sslMethod); + options->ctx = CTX_new(sslMethod); if (options->ctx == NULL) { printf_error("%sERROR: Could not create CTX object.%s\n", COL_RED, RESET); return false; @@ -170,7 +182,7 @@ int populateCipherList(struct sslCheckOptions *options, const SSL_METHOD *sslMet ssl = SSL_new(options->ctx); if (ssl == NULL) { printf_error("%sERROR: Could not create SSL object.%s\n", COL_RED, RESET); - SSL_CTX_free(options->ctx); + CTX_FREE(options->ctx); return false; } cipherList = SSL_get_ciphers(ssl); @@ -200,7 +212,7 @@ int populateCipherList(struct sslCheckOptions *options, const SSL_METHOD *sslMet sslCipherPointer->bits = SSL_CIPHER_get_bits(sk_SSL_CIPHER_value(cipherList, loop), &tempInt); } SSL_free(ssl); - SSL_CTX_free(options->ctx); + CTX_FREE(options->ctx); return returnCode; } @@ -831,7 +843,7 @@ int testCompression(struct sslCheckOptions *options, const SSL_METHOD *sslMethod if (socketDescriptor != 0) { // Setup Context Object... - options->ctx = SSL_CTX_new(sslMethod); + options->ctx = CTX_new(sslMethod); tls_reneg_init(options); if (options->ctx != NULL) { @@ -918,7 +930,7 @@ int testCompression(struct sslCheckOptions *options, const SSL_METHOD *sslMethod printf_error("%s ERROR: Could set cipher.%s\n", COL_RED, RESET); } // Free CTX Object - SSL_CTX_free(options->ctx); + CTX_FREE(options->ctx); } // Error Creating Context Object else @@ -967,7 +979,7 @@ int testFallback(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) if (socketDescriptor != 0) { // Setup Context Object... - options->ctx = SSL_CTX_new(sslMethod); + options->ctx = CTX_new(sslMethod); tls_reneg_init(options); if (options->ctx != NULL) { @@ -1087,7 +1099,7 @@ int testFallback(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) printf_error("%s ERROR: Could set cipher.%s\n", COL_RED, RESET); } // Free CTX Object - SSL_CTX_free(options->ctx); + CTX_FREE(options->ctx); } // Error Creating Context Object else @@ -1136,7 +1148,7 @@ int testRenegotiation(struct sslCheckOptions *options, const SSL_METHOD *sslMeth { // Setup Context Object... - options->ctx = SSL_CTX_new(sslMethod); + options->ctx = CTX_new(sslMethod); tls_reneg_init(options); if (options->ctx != NULL) { @@ -1273,7 +1285,7 @@ int testRenegotiation(struct sslCheckOptions *options, const SSL_METHOD *sslMeth printf_error("%s ERROR: Could set cipher.%s\n", COL_RED, RESET); } // Free CTX Object - SSL_CTX_free(options->ctx); + CTX_FREE(options->ctx); } // Error Creating Context Object else @@ -1827,7 +1839,7 @@ int checkCertificateProtocol(struct sslCheckOptions *options, const SSL_METHOD * { int status = true; // Setup Context Object... - options->ctx = SSL_CTX_new(sslMethod); + options->ctx = CTX_new(sslMethod); if (options->ctx != NULL) { // SSL implementation bugs/workaround @@ -1876,7 +1888,7 @@ int checkCertificate(struct sslCheckOptions *options, const SSL_METHOD *sslMetho if (socketDescriptor != 0) { // Setup Context Object... - options->ctx = SSL_CTX_new(sslMethod); + options->ctx = CTX_new(sslMethod); if (options->ctx != NULL) { @@ -2236,7 +2248,7 @@ int checkCertificate(struct sslCheckOptions *options, const SSL_METHOD *sslMetho } // Free CTX Object - SSL_CTX_free(options->ctx); + CTX_FREE(options->ctx); } // Error Creating Context Object else @@ -2296,7 +2308,7 @@ int ocspRequest(struct sslCheckOptions *options) printf_verbose("If server doesn't support TLSv1.0, manually specify TLS version\n"); sslMethod = TLSv1_method(); } - options->ctx = SSL_CTX_new(sslMethod); + options->ctx = CTX_new(sslMethod); if (options->ctx != NULL) { @@ -2380,7 +2392,7 @@ int ocspRequest(struct sslCheckOptions *options) } // Free CTX Object - SSL_CTX_free(options->ctx); + CTX_FREE(options->ctx); } // Error Creating Context Object else @@ -2475,7 +2487,7 @@ int showCertificate(struct sslCheckOptions *options) printf_verbose("If server doesn't support TLSv1.0, manually specificy TLS version\n"); sslMethod = TLSv1_method(); } - options->ctx = SSL_CTX_new(sslMethod); + options->ctx = CTX_new(sslMethod); if (options->ctx != NULL) { if (SSL_CTX_set_cipher_list(options->ctx, CIPHERSUITE_LIST_ALL) != 0) @@ -2858,7 +2870,7 @@ int showCertificate(struct sslCheckOptions *options) } // Free CTX Object - SSL_CTX_free(options->ctx); + CTX_FREE(options->ctx); } // Error Creating Context Object @@ -2926,7 +2938,7 @@ int showTrustedCAs(struct sslCheckOptions *options) printf_verbose("If server doesn't support TLSv1.0, manually specificy TLS version\n"); sslMethod = TLSv1_method(); } - options->ctx = SSL_CTX_new(sslMethod); + options->ctx = CTX_new(sslMethod); if (options->ctx != NULL) { if (SSL_CTX_set_cipher_list(options->ctx, CIPHERSUITE_LIST_ALL) != 0) @@ -3027,7 +3039,7 @@ int showTrustedCAs(struct sslCheckOptions *options) } // Free CTX Object - SSL_CTX_free(options->ctx); + CTX_FREE(options->ctx); } // Error Creating Context Object @@ -3129,7 +3141,7 @@ int testProtocolCiphers(struct sslCheckOptions *options, const SSL_METHOD *sslMe while (status == true) { // Setup Context Object... - options->ctx = SSL_CTX_new(sslMethod); + options->ctx = CTX_new(sslMethod); if (options->ctx != NULL) { // SSL implementation bugs/workaround @@ -3151,7 +3163,7 @@ int testProtocolCiphers(struct sslCheckOptions *options, const SSL_METHOD *sslMe status = testCipher(options, sslMethod); // Free CTX Object - SSL_CTX_free(options->ctx); + CTX_FREE(options->ctx); } // Error Creating Context Object diff --git a/sslscan.h b/sslscan.h index 806e39a..8461c92 100644 --- a/sslscan.h +++ b/sslscan.h @@ -61,7 +61,7 @@ #define TLSV13_CIPHERSUITES "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256" /* Somehow, RC4-MD5 is silently excluded in the latest OpenSSL release unless its explicitly included. */ -#define CIPHERSUITE_LIST_ALL "ALL:COMPLEMENTOFALL:RC4-MD5:@SECLEVEL=0" +#define CIPHERSUITE_LIST_ALL "ALL:COMPLEMENTOFALL" // Macros for various outputs #define printf(format, ...) if (!xml_to_stdout) fprintf(stdout, format, ##__VA_ARGS__) @@ -69,6 +69,8 @@ #define printf_xml(format, ...) if (options->xmlOutput) fprintf(options->xmlOutput, format, ##__VA_ARGS__) #define printf_verbose(format, ...) if (options->verbose) printf(format, ##__VA_ARGS__) +#define CTX_FREE(ctx) { SSL_CTX_free((ctx)); (ctx) = NULL; } + // Colour Console Output... // Always better to do "const char RESET[] = " because it saves relocation records. // Default colours were hard to read on Windows, so use lighter ones @@ -195,6 +197,7 @@ struct renegotiationOutput #endif // Utilities +SSL_CTX *CTX_new(const SSL_METHOD *method); int fileExists(char *); void readLine(FILE *, char *, int); ssize_t sendString(int, const char[]); From 5f42d2e67fd9b7897733562f2257f62ae4620f46 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Fri, 6 Dec 2019 00:45:20 -0500 Subject: [PATCH 23/52] Improved buffer handling for HTTP response code parsing. --- sslscan.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/sslscan.c b/sslscan.c index e834588..bda549a 100644 --- a/sslscan.c +++ b/sslscan.c @@ -1581,15 +1581,13 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) const char *cleanSslMethod = printableSslMethod(sslMethod); const char *ciphername; struct timeval tval_start, tval_end, tval_elapsed; + + if (options->showTimes) { gettimeofday(&tval_start, NULL); } - // Create request buffer... - memset(requestBuffer, 0, 200); - snprintf(requestBuffer, 199, "GET / HTTP/1.0\r\nUser-Agent: SSLScan\r\nHost: %s\r\n\r\n", options->host); - // Connect to host socketDescriptor = tcpConnect(options); if (socketDescriptor != 0) @@ -1654,14 +1652,18 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) BIO_set_fp(stdoutBIO, stdout, BIO_NOCLOSE); } + // Create request buffer... + memset(requestBuffer, 0, sizeof(requestBuffer)); + snprintf(requestBuffer, sizeof(requestBuffer) - 1, "GET / HTTP/1.0\r\nUser-Agent: SSLScan\r\nHost: %s\r\n\r\n", options->host); + // HTTP Get... - SSL_write(ssl, requestBuffer, sizeof(requestBuffer)); - memset(buffer ,0 , 50); - resultSize = SSL_read(ssl, buffer, 49); + SSL_write(ssl, requestBuffer, strlen(requestBuffer)); + memset(buffer, 0, sizeof(buffer)); + resultSize = SSL_read(ssl, buffer, sizeof(buffer) - 1); if (resultSize > 9) { int loop = 0; - for (loop = 9; (loop < 49) && (buffer[loop] != 0) && (buffer[loop] != '\r') && (buffer[loop] != '\n'); loop++) + for (loop = 9; (loop < sizeof(buffer) - 1) && (buffer[loop] != 0) && (buffer[loop] != '\r') && (buffer[loop] != '\n'); loop++) { } buffer[loop] = 0; From 090ab7b2ef1fd89be1407528c678303e62b79d7c Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Fri, 6 Dec 2019 00:47:49 -0500 Subject: [PATCH 24/52] Updated comments and added CTX_FREE() and SSL_FREE() macros. --- sslscan.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sslscan.h b/sslscan.h index 8461c92..7fd5879 100644 --- a/sslscan.h +++ b/sslscan.h @@ -60,7 +60,7 @@ /* We must maintain our own list of TLSv1.3-specific ciphersuites here, because SSL_CTX_get_ciphers() will *always* return TLSv1.2 ciphersuites, even when SSL_CTX_set_min_proto_version() and SSL_CTX_set_max_proto_version() are used. This is confirmed by an OpenSSL developer here: https://github.com/openssl/openssl/issues/7196#issuecomment-420575202 */ #define TLSV13_CIPHERSUITES "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256" -/* Somehow, RC4-MD5 is silently excluded in the latest OpenSSL release unless its explicitly included. */ +/* Cipherlist for TLSv1.2 and below that corresponds to all available ciphersuites. */ #define CIPHERSUITE_LIST_ALL "ALL:COMPLEMENTOFALL" // Macros for various outputs @@ -69,6 +69,10 @@ #define printf_xml(format, ...) if (options->xmlOutput) fprintf(options->xmlOutput, format, ##__VA_ARGS__) #define printf_verbose(format, ...) if (options->verbose) printf(format, ##__VA_ARGS__) +/* Frees an SSL pointer, and explicitly sets it to NULL to avoid use-after-free. */ +#define SSL_FREE(ssl) { SSL_free((ssl)); (ssl) = NULL; } + +/* Frees a SSL_CTX pointer, and explicitly sets it to NULL to avoid use-after-free. */ #define CTX_FREE(ctx) { SSL_CTX_free((ctx)); (ctx) = NULL; } // Colour Console Output... From eb35e9091999c8f6b5721fa28ebdee6a1479de1c Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Fri, 6 Dec 2019 00:51:11 -0500 Subject: [PATCH 25/52] Replaced SSL_free() with SSL_FREE() macro to ensure use-after-free does not happen. --- sslscan.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sslscan.c b/sslscan.c index bda549a..258a75b 100644 --- a/sslscan.c +++ b/sslscan.c @@ -211,7 +211,7 @@ int populateCipherList(struct sslCheckOptions *options, const SSL_METHOD *sslMet 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); } - SSL_free(ssl); + SSL_FREE(ssl); CTX_FREE(options->ctx); return returnCode; } @@ -915,7 +915,7 @@ int testCompression(struct sslCheckOptions *options, const SSL_METHOD *sslMethod SSL_shutdown(ssl); // Free SSL object - SSL_free(ssl); + SSL_FREE(ssl); } else { @@ -1084,7 +1084,7 @@ int testFallback(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) SSL_shutdown(ssl); // Free SSL object - SSL_free(ssl); + SSL_FREE(ssl); } else { @@ -1268,7 +1268,7 @@ int testRenegotiation(struct sslCheckOptions *options, const SSL_METHOD *sslMeth } // Free SSL object - SSL_free(ssl); + SSL_FREE(ssl); } else { @@ -1812,7 +1812,7 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) } // Free SSL object - SSL_free(ssl); + SSL_FREE(ssl); } else { @@ -2234,7 +2234,7 @@ int checkCertificate(struct sslCheckOptions *options, const SSL_METHOD *sslMetho SSL_shutdown(ssl); } // Free SSL object - SSL_free(ssl); + SSL_FREE(ssl); } else { @@ -2378,7 +2378,7 @@ int ocspRequest(struct sslCheckOptions *options) printf("Most likely cause is server not supporting %s, try manually specifying version\n", printableSslMethod(sslMethod)); } // Free SSL object - SSL_free(ssl); + SSL_FREE(ssl); } else { @@ -2856,7 +2856,7 @@ int showCertificate(struct sslCheckOptions *options) } // Free SSL object - SSL_free(ssl); + SSL_FREE(ssl); } else { @@ -3025,7 +3025,7 @@ int showTrustedCAs(struct sslCheckOptions *options) } // Free SSL object - SSL_free(ssl); + SSL_FREE(ssl); } else { From 561e0d924010319d62b700b3f61a9a49f10774e2 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Fri, 6 Dec 2019 17:27:29 -0500 Subject: [PATCH 26/52] Re-enabled OCSP request parsing. --- sslscan.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++++------ sslscan.h | 69 +++++++++++++++++++++- 2 files changed, 219 insertions(+), 21 deletions(-) diff --git a/sslscan.c b/sslscan.c index 258a75b..c97ba90 100644 --- a/sslscan.c +++ b/sslscan.c @@ -2414,27 +2414,160 @@ int ocspRequest(struct sslCheckOptions *options) return status; } -static int ocsp_resp_cb(SSL *s, void *arg) -{ - const unsigned char *p; - int len; - OCSP_RESPONSE *rsp; - len = SSL_get_tlsext_status_ocsp_resp(s, &p); - BIO_puts(arg, "OCSP response: "); +static int ocsp_resp_cb(SSL *s, void *unused) { + const unsigned char *p = NULL; + int len = 0; + OCSP_RESPONSE *o = NULL; + BIO *bp = BIO_new_fp(stdout, BIO_NOCLOSE); + int i = 0; + long l = 0; + OCSP_CERTID *cid = NULL; + OCSP_BASICRESP *br = NULL; + OCSP_RESPID *rid = NULL; + OCSP_RESPDATA *rd = NULL; + OCSP_CERTSTATUS *cst = NULL; + OCSP_REVOKEDINFO *rev = NULL; + OCSP_SINGLERESP *single = NULL; + OCSP_RESPBYTES *rb = NULL; + + + len = SSL_get_tlsext_status_ocsp_resp(s, &p); if (p == NULL) { - BIO_puts(arg, "no response sent\n"); - return 1; - } - rsp = d2i_OCSP_RESPONSE(NULL, &p, len); - if (rsp == NULL) { - BIO_puts(arg, "response parse error\n"); - BIO_dump_indent(arg, (char *)p, len, 4); - return 0; + BIO_puts(bp, "No OCSP response recieved.\n\n"); + goto err; + } + + o = d2i_OCSP_RESPONSE(NULL, &p, len); + if (o == NULL) { + BIO_puts(bp, "OCSP response parse error\n"); + BIO_dump_indent(bp, (char *)p, len, 4); + goto err; + } + + rb = o->responseBytes; + l = ASN1_ENUMERATED_get(o->responseStatus); + if (BIO_printf(bp, "OCSP Response Status: %s (0x%lx)\n", + OCSP_response_status_str(l), l) <= 0) + goto err; + if (rb == NULL) + return 1; + if (BIO_puts(bp, "Response Type: ") <= 0) + goto err; + if (i2a_ASN1_OBJECT(bp, rb->responseType) <= 0) + goto err; + if (OBJ_obj2nid(rb->responseType) != NID_id_pkix_OCSP_basic) { + BIO_puts(bp, " (unknown response type)\n"); + return 1; + } + + if ((br = OCSP_response_get1_basic(o)) == NULL) + goto err; + rd = &br->tbsResponseData; + l = ASN1_INTEGER_get(rd->version); + if (BIO_printf(bp, "\nVersion: %lu (0x%lx)\n", l + 1, l) <= 0) + goto err; + if (BIO_puts(bp, "Responder Id: ") <= 0) + goto err; + + rid = &rd->responderId; + switch (rid->type) { + case V_OCSP_RESPID_NAME: + X509_NAME_print_ex(bp, rid->value.byName, 0, XN_FLAG_ONELINE); + break; + case V_OCSP_RESPID_KEY: + i2a_ASN1_STRING(bp, rid->value.byKey, 0); + break; + } + + if (BIO_printf(bp, "\nProduced At: ") <= 0) + goto err; + if (!ASN1_GENERALIZEDTIME_print(bp, rd->producedAt)) + goto err; + if (BIO_printf(bp, "\nResponses:\n") <= 0) + goto err; + for (i = 0; i < sk_OCSP_SINGLERESP_num(rd->responses); i++) { + if (!sk_OCSP_SINGLERESP_value(rd->responses, i)) + continue; + single = sk_OCSP_SINGLERESP_value(rd->responses, i); + cid = single->certId; + if (ocsp_certid_print(bp, cid, 4) <= 0) + goto err; + cst = single->certStatus; + if (BIO_puts(bp, " Cert Status: ") <= 0) + goto err; + if (cst->type == V_OCSP_CERTSTATUS_GOOD) { + if (BIO_printf(bp, "%s%s%s", COL_GREEN, OCSP_cert_status_str(cst->type), RESET) <= 0) + goto err; + } else if (cst->type == V_OCSP_CERTSTATUS_REVOKED) { + if (BIO_printf(bp, "%s%s%s", COL_RED, OCSP_cert_status_str(cst->type), RESET) <= 0) + goto err; + rev = cst->value.revoked; + if (BIO_printf(bp, "\n Revocation Time: ") <= 0) + goto err; + if (!ASN1_GENERALIZEDTIME_print(bp, rev->revocationTime)) + goto err; + if (rev->revocationReason) { + l = ASN1_ENUMERATED_get(rev->revocationReason); + if (BIO_printf(bp, + "\n Revocation Reason: %s (0x%lx)", + OCSP_crl_reason_str(l), l) <= 0) + goto err; + } + } else { + if (BIO_printf(bp, "%s%s%s", COL_YELLOW, OCSP_cert_status_str(cst->type), RESET) <= 0) + goto err; } - BIO_puts(arg, "\n======================================\n"); - OCSP_RESPONSE_print(arg, rsp, 0); - BIO_puts(arg, "======================================\n"); - OCSP_RESPONSE_free(rsp); + if (BIO_printf(bp, "\n This Update: ") <= 0) + goto err; + if (!ASN1_GENERALIZEDTIME_print(bp, single->thisUpdate)) + goto err; + if (single->nextUpdate) { + if (BIO_printf(bp, "\n Next Update: ") <= 0) + goto err; + if (!ASN1_GENERALIZEDTIME_print(bp, single->nextUpdate)) + goto err; + } + if (BIO_write(bp, "\n", 1) <= 0) + goto err; + + if (!X509V3_extensions_print(bp, + "Response Single Extensions", + single->singleExtensions, 0, 4)) + goto err; + if (BIO_write(bp, "\n", 1) <= 0) + goto err; + } + /* + if (!X509V3_extensions_print(bp, "Response Extensions", + rd->responseExtensions, 0, 4)) + goto err; + if (X509_signature_print(bp, &br->signatureAlgorithm, br->signature) <= 0) + goto err; + + for (i = 0; i < sk_X509_num(br->certs); i++) { + X509_print(bp, sk_X509_value(br->certs, i)); + PEM_write_bio_X509(bp, sk_X509_value(br->certs, i)); + } + */ + err: + if (o != NULL) { OCSP_RESPONSE_free(o); o = NULL; } + BIO_free(bp); + return 1; +} + +int ocsp_certid_print(BIO *bp, OCSP_CERTID *a, int indent) +{ + BIO_printf(bp, "%*sCertificate ID:\n", indent, ""); + indent += 2; + BIO_printf(bp, "%*sHash Algorithm: ", indent, ""); + i2a_ASN1_OBJECT(bp, a->hashAlgorithm.algorithm); + BIO_printf(bp, "\n%*sIssuer Name Hash: ", indent, ""); + i2a_ASN1_STRING(bp, &a->issuerNameHash, 0); + BIO_printf(bp, "\n%*sIssuer Key Hash: ", indent, ""); + i2a_ASN1_STRING(bp, &a->issuerKeyHash, 0); + BIO_printf(bp, "\n%*sSerial Number: ", indent, ""); + i2a_ASN1_INTEGER(bp, &a->serialNumber); + BIO_printf(bp, "\n"); return 1; } diff --git a/sslscan.h b/sslscan.h index 7fd5879..fab9737 100644 --- a/sslscan.h +++ b/sslscan.h @@ -70,10 +70,10 @@ #define printf_verbose(format, ...) if (options->verbose) printf(format, ##__VA_ARGS__) /* Frees an SSL pointer, and explicitly sets it to NULL to avoid use-after-free. */ -#define SSL_FREE(ssl) { SSL_free((ssl)); (ssl) = NULL; } +#define SSL_FREE(ssl) { if (ssl != NULL) { SSL_free((ssl)); (ssl) = NULL; } } /* Frees a SSL_CTX pointer, and explicitly sets it to NULL to avoid use-after-free. */ -#define CTX_FREE(ctx) { SSL_CTX_free((ctx)); (ctx) = NULL; } +#define CTX_FREE(ctx) { if (ctx != NULL) { SSL_CTX_free((ctx)); (ctx) = NULL; } } // Colour Console Output... // Always better to do "const char RESET[] = " because it saves relocation records. @@ -189,6 +189,71 @@ struct renegotiationOutput int secure; }; +/* For OCSP processing. Taken from crypto/ocsp/ocsp_local.h in OpenSSL, which does not seem to be normally exposed externally. */ +struct ocsp_response_st { + ASN1_ENUMERATED *responseStatus; + OCSP_RESPBYTES *responseBytes; +}; + +struct ocsp_resp_bytes_st { + ASN1_OBJECT *responseType; + ASN1_OCTET_STRING *response; +}; + +struct ocsp_responder_id_st { + int type; + union { + X509_NAME *byName; + ASN1_OCTET_STRING *byKey; + } value; +}; +typedef struct ocsp_responder_id_st OCSP_RESPID; + +struct ocsp_response_data_st { + ASN1_INTEGER *version; + OCSP_RESPID responderId; + ASN1_GENERALIZEDTIME *producedAt; + STACK_OF(OCSP_SINGLERESP) *responses; + STACK_OF(X509_EXTENSION) *responseExtensions; +}; +typedef struct ocsp_response_data_st OCSP_RESPDATA; + +struct ocsp_basic_response_st { + OCSP_RESPDATA tbsResponseData; + X509_ALGOR signatureAlgorithm; + ASN1_BIT_STRING *signature; + STACK_OF(X509) *certs; +}; + +struct ocsp_single_response_st { + OCSP_CERTID *certId; + OCSP_CERTSTATUS *certStatus; + ASN1_GENERALIZEDTIME *thisUpdate; + ASN1_GENERALIZEDTIME *nextUpdate; + STACK_OF(X509_EXTENSION) *singleExtensions; +}; + +struct ocsp_cert_status_st { + int type; + union { + ASN1_NULL *good; + OCSP_REVOKEDINFO *revoked; + ASN1_NULL *unknown; + } value; +}; + +struct ocsp_revoked_info_st { + ASN1_GENERALIZEDTIME *revocationTime; + ASN1_ENUMERATED *revocationReason; +}; + +struct ocsp_cert_id_st { + X509_ALGOR hashAlgorithm; + ASN1_OCTET_STRING issuerNameHash; + ASN1_OCTET_STRING issuerKeyHash; + ASN1_INTEGER serialNumber; +}; + /* We redefine these so that we can run correctly even if the vendor gives us * a version of OpenSSL that does not match its header files. (Apple: I am * looking at you.) From 938e51a50316732056e4b844a5ed576029df1fce Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Fri, 6 Dec 2019 17:59:18 -0500 Subject: [PATCH 27/52] Don't run SSLv2 & SSLv3 tests if user specified --no-ciphersuites. --- sslscan.c | 49 +++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/sslscan.c b/sslscan.c index c97ba90..b958089 100644 --- a/sslscan.c +++ b/sslscan.c @@ -3440,32 +3440,33 @@ int testHost(struct sslCheckOptions *options) #endif } - printf(" %sSSL Protocols:%s\n", COL_BLUE, RESET); - // Check if SSLv2 is enabled. - if ((options->sslVersion == ssl_all) || (options->sslVersion == ssl_v2)) { - if (runSSLv2Test(options)) { - printf("SSLv2 is %senabled%s\n", COL_RED, RESET); - printf_xml(" \n"); - } else { - printf("SSLv2 is %snot enabled%s\n", COL_GREEN, RESET); - printf_xml(" \n"); - } - } - - // Check if SSLv3 is enabled. - if ((options->sslVersion == ssl_all) || (options->sslVersion == ssl_v3)) { - if (runSSLv3Test(options)) { - printf("SSLv3 is %senabled%s\n", COL_RED, RESET); - printf_xml(" \n"); - } else { - printf("SSLv3 is %snot enabled%s\n", COL_GREEN, RESET); - printf_xml(" \n"); - } - } - printf("\n"); - if (options->ciphersuites) { + printf(" %sSSL Protocols:%s\n", COL_BLUE, RESET); + + // Check if SSLv2 is enabled. + if ((options->sslVersion == ssl_all) || (options->sslVersion == ssl_v2)) { + if (runSSLv2Test(options)) { + printf("SSLv2 is %senabled%s\n", COL_RED, RESET); + printf_xml(" \n"); + } else { + printf("SSLv2 is %snot enabled%s\n", COL_GREEN, RESET); + printf_xml(" \n"); + } + } + + // Check if SSLv3 is enabled. + if ((options->sslVersion == ssl_all) || (options->sslVersion == ssl_v3)) { + if (runSSLv3Test(options)) { + printf("SSLv3 is %senabled%s\n", COL_RED, RESET); + printf_xml(" \n"); + } else { + printf("SSLv3 is %snot enabled%s\n", COL_GREEN, RESET); + printf_xml(" \n"); + } + } + printf("\n"); + // Test supported ciphers... printf(" %sSupported Server Cipher(s):%s\n", COL_BLUE, RESET); switch (options->sslVersion) From 4e84602e01770443af46e7297334d177786ce4a2 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Mon, 9 Dec 2019 10:53:33 -0500 Subject: [PATCH 28/52] Updated Curve25519 & Curve448 output to be more consistent with P-256, etc. --- sslscan.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sslscan.c b/sslscan.c index b958089..8af2fac 100644 --- a/sslscan.c +++ b/sslscan.c @@ -1511,10 +1511,12 @@ int ssl_print_tmp_key(struct sslCheckOptions *options, SSL *s) } break; case EVP_PKEY_X25519: - printf(" %sX25519%s", COL_GREEN, RESET); + printf(" Curve %s25519%s DHE %d", COL_GREEN, RESET, EVP_PKEY_bits(key)); + printf_xml(" curve=\"25519\" ecdhebits=\"%d\"", EVP_PKEY_bits(key)); break; case EVP_PKEY_X448: - printf(" %sX448%s", COL_GREEN, RESET); + printf(" Curve %s448%s DHE %d", COL_GREEN, RESET, EVP_PKEY_bits(key)); + printf_xml(" curve=\"448\" ecdhebits=\"%d\"", EVP_PKEY_bits(key)); break; default: printf(" %sUnknown ID (%d)%s", COL_YELLOW, EVP_PKEY_id(key), RESET); From 75cc22b513782f032abc21aa2b6dd7fe801c65b2 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Mon, 9 Dec 2019 11:19:16 -0500 Subject: [PATCH 29/52] Replaced -DOPENSSL_TLS_SECURITY_LEVEL=0 compile flag with SSL_set_security_level() and SSL_CTX_set_security_level() at run-time. Renamed CTX_new() to new_CTX() to match new_SSL(). --- Makefile | 4 +-- sslscan.c | 89 ++++++++++++++++++++++++++++++------------------------- sslscan.h | 4 +-- 3 files changed, 53 insertions(+), 44 deletions(-) diff --git a/Makefile b/Makefile index 0ce7602..a3880e1 100644 --- a/Makefile +++ b/Makefile @@ -127,11 +127,11 @@ opensslpull: # Need to build OpenSSL differently on OSX ifeq ($(OS), Darwin) openssl/Makefile: .openssl.is.fresh - cd ./openssl; ./Configure -fstack-protector-all -D_FORTIFY_SOURCE=2 -DOPENSSL_TLS_SECURITY_LEVEL=0 -fPIC enable-weak-ssl-ciphers zlib darwin64-x86_64-cc + cd ./openssl; ./Configure -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIC enable-weak-ssl-ciphers zlib darwin64-x86_64-cc # Any other *NIX platform else openssl/Makefile: .openssl.is.fresh - cd ./openssl; ./config -v -fstack-protector-all -D_FORTIFY_SOURCE=2 -DOPENSSL_TLS_SECURITY_LEVEL=0 -fPIC no-shared enable-weak-ssl-ciphers zlib + cd ./openssl; ./config -v -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIC no-shared enable-weak-ssl-ciphers zlib endif openssl/libcrypto.a: openssl/Makefile diff --git a/sslscan.c b/sslscan.c index 8af2fac..4e9d53b 100644 --- a/sslscan.c +++ b/sslscan.c @@ -156,13 +156,22 @@ static int security_callback_allow_all(const SSL *s, const SSL_CTX *ctx, int op, return 1; } -/* Creates an SSL_CTX using CTX_new(), and sets the permissive security callback on it. Free with CTX_FREE(). */ -SSL_CTX *CTX_new(const SSL_METHOD *method) { +/* Creates an SSL_CTX using SSL_CTX_new(), sets the security level to 0, and sets the permissive security callback on it. Free with FREE_CTX(). */ +SSL_CTX *new_CTX(const SSL_METHOD *method) { SSL_CTX *ret = SSL_CTX_new(method); + SSL_CTX_set_security_level(ret, 0); SSL_CTX_set_security_callback(ret, security_callback_allow_all); return ret; } +/* Creates an SSL object using SSL_new(), sets the security level to 0, and sets the permissive security callback on it. Free with FREE_SSL(). */ +SSL *new_SSL(SSL_CTX *ctx) { + SSL *ret = SSL_new(ctx); + SSL_set_security_level(ret, 0); + SSL_set_security_callback(ret, security_callback_allow_all); + return ret; +} + // Adds Ciphers to the Cipher List structure int populateCipherList(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) { @@ -173,16 +182,16 @@ int populateCipherList(struct sslCheckOptions *options, const SSL_METHOD *sslMet // STACK_OF is a sign that you should be using C++ :) STACK_OF(SSL_CIPHER) *cipherList; SSL *ssl = NULL; - options->ctx = CTX_new(sslMethod); + options->ctx = new_CTX(sslMethod); if (options->ctx == NULL) { printf_error("%sERROR: Could not create CTX object.%s\n", COL_RED, RESET); return false; } SSL_CTX_set_cipher_list(options->ctx, CIPHERSUITE_LIST_ALL); - ssl = SSL_new(options->ctx); + ssl = new_SSL(options->ctx); if (ssl == NULL) { printf_error("%sERROR: Could not create SSL object.%s\n", COL_RED, RESET); - CTX_FREE(options->ctx); + FREE_CTX(options->ctx); return false; } cipherList = SSL_get_ciphers(ssl); @@ -211,8 +220,8 @@ int populateCipherList(struct sslCheckOptions *options, const SSL_METHOD *sslMet 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); } - SSL_FREE(ssl); - CTX_FREE(options->ctx); + FREE_SSL(ssl); + FREE_CTX(options->ctx); return returnCode; } @@ -843,7 +852,7 @@ int testCompression(struct sslCheckOptions *options, const SSL_METHOD *sslMethod if (socketDescriptor != 0) { // Setup Context Object... - options->ctx = CTX_new(sslMethod); + options->ctx = new_CTX(sslMethod); tls_reneg_init(options); if (options->ctx != NULL) { @@ -857,7 +866,7 @@ int testCompression(struct sslCheckOptions *options, const SSL_METHOD *sslMethod if (status == true) { // Create SSL object... - ssl = SSL_new(options->ctx); + ssl = new_SSL(options->ctx); #if ( OPENSSL_VERSION_NUMBER > 0x009080cfL ) // Make sure we can connect to insecure servers @@ -915,7 +924,7 @@ int testCompression(struct sslCheckOptions *options, const SSL_METHOD *sslMethod SSL_shutdown(ssl); // Free SSL object - SSL_FREE(ssl); + FREE_SSL(ssl); } else { @@ -930,7 +939,7 @@ int testCompression(struct sslCheckOptions *options, const SSL_METHOD *sslMethod printf_error("%s ERROR: Could set cipher.%s\n", COL_RED, RESET); } // Free CTX Object - CTX_FREE(options->ctx); + FREE_CTX(options->ctx); } // Error Creating Context Object else @@ -979,7 +988,7 @@ int testFallback(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) if (socketDescriptor != 0) { // Setup Context Object... - options->ctx = CTX_new(sslMethod); + options->ctx = new_CTX(sslMethod); tls_reneg_init(options); if (options->ctx != NULL) { @@ -997,7 +1006,7 @@ int testFallback(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) if (status == true) { // Create SSL object... - ssl = SSL_new(options->ctx); + ssl = new_SSL(options->ctx); #if ( OPENSSL_VERSION_NUMBER > 0x009080cfL ) // Make sure we can connect to insecure servers @@ -1084,7 +1093,7 @@ int testFallback(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) SSL_shutdown(ssl); // Free SSL object - SSL_FREE(ssl); + FREE_SSL(ssl); } else { @@ -1099,7 +1108,7 @@ int testFallback(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) printf_error("%s ERROR: Could set cipher.%s\n", COL_RED, RESET); } // Free CTX Object - CTX_FREE(options->ctx); + FREE_CTX(options->ctx); } // Error Creating Context Object else @@ -1148,7 +1157,7 @@ int testRenegotiation(struct sslCheckOptions *options, const SSL_METHOD *sslMeth { // Setup Context Object... - options->ctx = CTX_new(sslMethod); + options->ctx = new_CTX(sslMethod); tls_reneg_init(options); if (options->ctx != NULL) { @@ -1162,7 +1171,7 @@ int testRenegotiation(struct sslCheckOptions *options, const SSL_METHOD *sslMeth if (status == true) { // Create SSL object... - ssl = SSL_new(options->ctx); + ssl = new_SSL(options->ctx); #if ( OPENSSL_VERSION_NUMBER > 0x009080cfL ) // Make sure we can connect to insecure servers @@ -1268,7 +1277,7 @@ int testRenegotiation(struct sslCheckOptions *options, const SSL_METHOD *sslMeth } // Free SSL object - SSL_FREE(ssl); + FREE_SSL(ssl); } else { @@ -1285,7 +1294,7 @@ int testRenegotiation(struct sslCheckOptions *options, const SSL_METHOD *sslMeth printf_error("%s ERROR: Could set cipher.%s\n", COL_RED, RESET); } // Free CTX Object - CTX_FREE(options->ctx); + FREE_CTX(options->ctx); } // Error Creating Context Object else @@ -1597,7 +1606,7 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) if (setCipherSuite(options, sslMethod, options->cipherstring)) { // Create SSL object... - ssl = SSL_new(options->ctx); + ssl = new_SSL(options->ctx); if (ssl != NULL) { @@ -1814,7 +1823,7 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) } // Free SSL object - SSL_FREE(ssl); + FREE_SSL(ssl); } else { @@ -1843,7 +1852,7 @@ int checkCertificateProtocol(struct sslCheckOptions *options, const SSL_METHOD * { int status = true; // Setup Context Object... - options->ctx = CTX_new(sslMethod); + options->ctx = new_CTX(sslMethod); if (options->ctx != NULL) { // SSL implementation bugs/workaround @@ -1892,7 +1901,7 @@ int checkCertificate(struct sslCheckOptions *options, const SSL_METHOD *sslMetho if (socketDescriptor != 0) { // Setup Context Object... - options->ctx = CTX_new(sslMethod); + options->ctx = new_CTX(sslMethod); if (options->ctx != NULL) { @@ -1905,7 +1914,7 @@ int checkCertificate(struct sslCheckOptions *options, const SSL_METHOD *sslMetho if (status == true) { // Create SSL object... - ssl = SSL_new(options->ctx); + ssl = new_SSL(options->ctx); if (ssl != NULL) { // Connect socket and BIO @@ -2236,7 +2245,7 @@ int checkCertificate(struct sslCheckOptions *options, const SSL_METHOD *sslMetho SSL_shutdown(ssl); } // Free SSL object - SSL_FREE(ssl); + FREE_SSL(ssl); } else { @@ -2252,7 +2261,7 @@ int checkCertificate(struct sslCheckOptions *options, const SSL_METHOD *sslMetho } // Free CTX Object - CTX_FREE(options->ctx); + FREE_CTX(options->ctx); } // Error Creating Context Object else @@ -2312,7 +2321,7 @@ int ocspRequest(struct sslCheckOptions *options) printf_verbose("If server doesn't support TLSv1.0, manually specify TLS version\n"); sslMethod = TLSv1_method(); } - options->ctx = CTX_new(sslMethod); + options->ctx = new_CTX(sslMethod); if (options->ctx != NULL) { @@ -2325,7 +2334,7 @@ int ocspRequest(struct sslCheckOptions *options) if (status == true) { // Create SSL object... - ssl = SSL_new(options->ctx); + ssl = new_SSL(options->ctx); if (ssl != NULL) { // Connect socket and BIO @@ -2380,7 +2389,7 @@ int ocspRequest(struct sslCheckOptions *options) printf("Most likely cause is server not supporting %s, try manually specifying version\n", printableSslMethod(sslMethod)); } // Free SSL object - SSL_FREE(ssl); + FREE_SSL(ssl); } else { @@ -2396,7 +2405,7 @@ int ocspRequest(struct sslCheckOptions *options) } // Free CTX Object - CTX_FREE(options->ctx); + FREE_CTX(options->ctx); } // Error Creating Context Object else @@ -2624,7 +2633,7 @@ int showCertificate(struct sslCheckOptions *options) printf_verbose("If server doesn't support TLSv1.0, manually specificy TLS version\n"); sslMethod = TLSv1_method(); } - options->ctx = CTX_new(sslMethod); + options->ctx = new_CTX(sslMethod); if (options->ctx != NULL) { if (SSL_CTX_set_cipher_list(options->ctx, CIPHERSUITE_LIST_ALL) != 0) @@ -2636,7 +2645,7 @@ int showCertificate(struct sslCheckOptions *options) if (status == true) { // Create SSL object... - ssl = SSL_new(options->ctx); + ssl = new_SSL(options->ctx); if (ssl != NULL) { // Connect socket and BIO @@ -2991,7 +3000,7 @@ int showCertificate(struct sslCheckOptions *options) } // Free SSL object - SSL_FREE(ssl); + FREE_SSL(ssl); } else { @@ -3007,7 +3016,7 @@ int showCertificate(struct sslCheckOptions *options) } // Free CTX Object - CTX_FREE(options->ctx); + FREE_CTX(options->ctx); } // Error Creating Context Object @@ -3075,7 +3084,7 @@ int showTrustedCAs(struct sslCheckOptions *options) printf_verbose("If server doesn't support TLSv1.0, manually specificy TLS version\n"); sslMethod = TLSv1_method(); } - options->ctx = CTX_new(sslMethod); + options->ctx = new_CTX(sslMethod); if (options->ctx != NULL) { if (SSL_CTX_set_cipher_list(options->ctx, CIPHERSUITE_LIST_ALL) != 0) @@ -3087,7 +3096,7 @@ int showTrustedCAs(struct sslCheckOptions *options) if (status == true) { // Create SSL object... - ssl = SSL_new(options->ctx); + ssl = new_SSL(options->ctx); if (ssl != NULL) { // Connect socket and BIO @@ -3160,7 +3169,7 @@ int showTrustedCAs(struct sslCheckOptions *options) } // Free SSL object - SSL_FREE(ssl); + FREE_SSL(ssl); } else { @@ -3176,7 +3185,7 @@ int showTrustedCAs(struct sslCheckOptions *options) } // Free CTX Object - CTX_FREE(options->ctx); + FREE_CTX(options->ctx); } // Error Creating Context Object @@ -3278,7 +3287,7 @@ int testProtocolCiphers(struct sslCheckOptions *options, const SSL_METHOD *sslMe while (status == true) { // Setup Context Object... - options->ctx = CTX_new(sslMethod); + options->ctx = new_CTX(sslMethod); if (options->ctx != NULL) { // SSL implementation bugs/workaround @@ -3300,7 +3309,7 @@ int testProtocolCiphers(struct sslCheckOptions *options, const SSL_METHOD *sslMe status = testCipher(options, sslMethod); // Free CTX Object - CTX_FREE(options->ctx); + FREE_CTX(options->ctx); } // Error Creating Context Object diff --git a/sslscan.h b/sslscan.h index fab9737..1aad0f2 100644 --- a/sslscan.h +++ b/sslscan.h @@ -70,10 +70,10 @@ #define printf_verbose(format, ...) if (options->verbose) printf(format, ##__VA_ARGS__) /* Frees an SSL pointer, and explicitly sets it to NULL to avoid use-after-free. */ -#define SSL_FREE(ssl) { if (ssl != NULL) { SSL_free((ssl)); (ssl) = NULL; } } +#define FREE_SSL(ssl) { if ((ssl) != NULL) { SSL_free((ssl)); (ssl) = NULL; } } /* Frees a SSL_CTX pointer, and explicitly sets it to NULL to avoid use-after-free. */ -#define CTX_FREE(ctx) { if (ctx != NULL) { SSL_CTX_free((ctx)); (ctx) = NULL; } } +#define FREE_CTX(ctx) { if ((ctx) != NULL) { SSL_CTX_free((ctx)); (ctx) = NULL; } } // Colour Console Output... // Always better to do "const char RESET[] = " because it saves relocation records. From dead93edcc3869bc2cece18ced1e65004f02d331 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Tue, 10 Dec 2019 22:34:02 -0500 Subject: [PATCH 30/52] Now tests all ciphersuites not implemented by OpenSSL using ClientHello/ServerHello parsing. --- missing_ciphersuites.h | 629 ++++++++++++++++++++++++ sslscan.c | 687 +++++++++++++++++++++------ sslscan.h | 26 +- tools/iana_tls_ciphersuite_parser.py | 96 ++++ 4 files changed, 1282 insertions(+), 156 deletions(-) create mode 100644 missing_ciphersuites.h create mode 100755 tools/iana_tls_ciphersuite_parser.py diff --git a/missing_ciphersuites.h b/missing_ciphersuites.h new file mode 100644 index 0000000..dcdf7d4 --- /dev/null +++ b/missing_ciphersuites.h @@ -0,0 +1,629 @@ +#ifndef _MISSING_CIPHERSUITES_H +#define _MISSING_CIPHERSUITES_H + + +/* At run-time, the findMissingCiphers() function will enumerate all the ciphers that OpenSSL knows of, and compares them each to the missing_ciphersuites list. Afterwards, the 'check_tls_versions' field will have the set of TLS versions that OpenSSL does not have an implementation for (i.e.: if the TLS_RSA_WITH_IDEA_CBC_SHA cipher is set to V1_2, then OpenSSL has an implementation for it for TLS v1.0 and v1.1, but not for v1.2). */ + + +#define V1_0 (1) +#define V1_1 (1 << 1) +#define V1_2 (1 << 2) +#define VALL (V1_0 | V1_1 | V1_2) + + +struct missing_ciphersuite { + unsigned short id; /* TLS protocol ID. */ + char protocol_name[48]; /* IANA name, as defined in the RFCs. */ + int bits; /* Bit strength of the cipher. -1 if unknown. */ + unsigned int check_tls_versions; /* OR'ed list of V1_? defines. Refers to TLS version that OpenSSL does not have a ciphersuite implementation for. Hence, it should be tested under this version of TLS. */ + unsigned int accepted_tls_versions; /* OR'ed list of V1_? defines. Set at run-time if this ciphersuite was accepted by the server by the specified TLS version. */ +}; + + +/* Auto-generated by ./iana_tls_ciphersuite_parser.py on December 10, 2019. */ +struct missing_ciphersuite missing_ciphersuites[] = { + {0x0000, "TLS_NULL_WITH_NULL_NULL", -1, VALL, 0}, + {0x0001, "TLS_RSA_WITH_NULL_MD5", -1, VALL, 0}, + {0x0002, "TLS_RSA_WITH_NULL_SHA", -1, VALL, 0}, + {0x0003, "TLS_RSA_EXPORT_WITH_RC4_40_MD5", 40, VALL, 0}, + {0x0004, "TLS_RSA_WITH_RC4_128_MD5", 128, VALL, 0}, + {0x0005, "TLS_RSA_WITH_RC4_128_SHA", 128, VALL, 0}, + {0x0006, "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5", 40, VALL, 0}, + {0x0007, "TLS_RSA_WITH_IDEA_CBC_SHA", 128, VALL, 0}, + {0x0008, "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA", 40, VALL, 0}, + {0x0009, "TLS_RSA_WITH_DES_CBC_SHA", 56, VALL, 0}, + {0x000A, "TLS_RSA_WITH_3DES_EDE_CBC_SHA", 112, VALL, 0}, + {0x000B, "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", 40, VALL, 0}, + {0x000C, "TLS_DH_DSS_WITH_DES_CBC_SHA", 56, VALL, 0}, + {0x000D, "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", 112, VALL, 0}, + {0x000E, "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", 40, VALL, 0}, + {0x000F, "TLS_DH_RSA_WITH_DES_CBC_SHA", 56, VALL, 0}, + {0x0010, "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", 112, VALL, 0}, + {0x0011, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", 40, VALL, 0}, + {0x0012, "TLS_DHE_DSS_WITH_DES_CBC_SHA", 56, VALL, 0}, + {0x0013, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", 112, VALL, 0}, + {0x0014, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", 40, VALL, 0}, + {0x0015, "TLS_DHE_RSA_WITH_DES_CBC_SHA", 56, VALL, 0}, + {0x0016, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", 112, VALL, 0}, + {0x0017, "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5", 40, VALL, 0}, + {0x0018, "TLS_DH_anon_WITH_RC4_128_MD5", 128, VALL, 0}, + {0x0019, "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA", 40, VALL, 0}, + {0x001A, "TLS_DH_anon_WITH_DES_CBC_SHA", 56, VALL, 0}, + {0x001B, "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA", 112, VALL, 0}, + {0x001E, "TLS_KRB5_WITH_DES_CBC_SHA", 56, VALL, 0}, + {0x001F, "TLS_KRB5_WITH_3DES_EDE_CBC_SHA", 112, VALL, 0}, + {0x0020, "TLS_KRB5_WITH_RC4_128_SHA", 128, VALL, 0}, + {0x0021, "TLS_KRB5_WITH_IDEA_CBC_SHA", 128, VALL, 0}, + {0x0022, "TLS_KRB5_WITH_DES_CBC_MD5", 56, VALL, 0}, + {0x0023, "TLS_KRB5_WITH_3DES_EDE_CBC_MD5", 112, VALL, 0}, + {0x0024, "TLS_KRB5_WITH_RC4_128_MD5", 128, VALL, 0}, + {0x0025, "TLS_KRB5_WITH_IDEA_CBC_MD5", 128, VALL, 0}, + {0x0026, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", 56, VALL, 0}, + {0x0027, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA", 40, VALL, 0}, + {0x0028, "TLS_KRB5_EXPORT_WITH_RC4_40_SHA", 40, VALL, 0}, + {0x0029, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", 56, VALL, 0}, + {0x002A, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5", 40, VALL, 0}, + {0x002B, "TLS_KRB5_EXPORT_WITH_RC4_40_MD5", 40, VALL, 0}, + {0x002C, "TLS_PSK_WITH_NULL_SHA", -1, VALL, 0}, + {0x002D, "TLS_DHE_PSK_WITH_NULL_SHA", -1, VALL, 0}, + {0x002E, "TLS_RSA_PSK_WITH_NULL_SHA", -1, VALL, 0}, + {0x002F, "TLS_RSA_WITH_AES_128_CBC_SHA", 128, VALL, 0}, + {0x0030, "TLS_DH_DSS_WITH_AES_128_CBC_SHA", 128, VALL, 0}, + {0x0031, "TLS_DH_RSA_WITH_AES_128_CBC_SHA", 128, VALL, 0}, + {0x0032, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", 128, VALL, 0}, + {0x0033, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", 128, VALL, 0}, + {0x0034, "TLS_DH_anon_WITH_AES_128_CBC_SHA", 128, VALL, 0}, + {0x0035, "TLS_RSA_WITH_AES_256_CBC_SHA", 256, VALL, 0}, + {0x0036, "TLS_DH_DSS_WITH_AES_256_CBC_SHA", 256, VALL, 0}, + {0x0037, "TLS_DH_RSA_WITH_AES_256_CBC_SHA", 256, VALL, 0}, + {0x0038, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", 256, VALL, 0}, + {0x0039, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", 256, VALL, 0}, + {0x003A, "TLS_DH_anon_WITH_AES_256_CBC_SHA", 256, VALL, 0}, + {0x003B, "TLS_RSA_WITH_NULL_SHA256", -1, VALL, 0}, + {0x003C, "TLS_RSA_WITH_AES_128_CBC_SHA256", 128, VALL, 0}, + {0x003D, "TLS_RSA_WITH_AES_256_CBC_SHA256", 256, VALL, 0}, + {0x003E, "TLS_DH_DSS_WITH_AES_128_CBC_SHA256", 128, VALL, 0}, + {0x003F, "TLS_DH_RSA_WITH_AES_128_CBC_SHA256", 128, VALL, 0}, + {0x0040, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", 128, VALL, 0}, + {0x0041, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA", 128, VALL, 0}, + {0x0042, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA", 128, VALL, 0}, + {0x0043, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA", 128, VALL, 0}, + {0x0044, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", 128, VALL, 0}, + {0x0045, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", 128, VALL, 0}, + {0x0046, "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA", 128, VALL, 0}, + {0x0067, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", 128, VALL, 0}, + {0x0068, "TLS_DH_DSS_WITH_AES_256_CBC_SHA256", 256, VALL, 0}, + {0x0069, "TLS_DH_RSA_WITH_AES_256_CBC_SHA256", 256, VALL, 0}, + {0x006A, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", 256, VALL, 0}, + {0x006B, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", 256, VALL, 0}, + {0x006C, "TLS_DH_anon_WITH_AES_128_CBC_SHA256", 128, VALL, 0}, + {0x006D, "TLS_DH_anon_WITH_AES_256_CBC_SHA256", 256, VALL, 0}, + {0x0084, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA", 256, VALL, 0}, + {0x0085, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA", 256, VALL, 0}, + {0x0086, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA", 256, VALL, 0}, + {0x0087, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", 256, VALL, 0}, + {0x0088, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", 256, VALL, 0}, + {0x0089, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA", 256, VALL, 0}, + {0x008A, "TLS_PSK_WITH_RC4_128_SHA", 128, VALL, 0}, + {0x008B, "TLS_PSK_WITH_3DES_EDE_CBC_SHA", 112, VALL, 0}, + {0x008C, "TLS_PSK_WITH_AES_128_CBC_SHA", 128, VALL, 0}, + {0x008D, "TLS_PSK_WITH_AES_256_CBC_SHA", 256, VALL, 0}, + {0x008E, "TLS_DHE_PSK_WITH_RC4_128_SHA", 128, VALL, 0}, + {0x008F, "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA", 112, VALL, 0}, + {0x0090, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA", 128, VALL, 0}, + {0x0091, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA", 256, VALL, 0}, + {0x0092, "TLS_RSA_PSK_WITH_RC4_128_SHA", 128, VALL, 0}, + {0x0093, "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA", 112, VALL, 0}, + {0x0094, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA", 128, VALL, 0}, + {0x0095, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA", 256, VALL, 0}, + {0x0096, "TLS_RSA_WITH_SEED_CBC_SHA", -1, VALL, 0}, + {0x0097, "TLS_DH_DSS_WITH_SEED_CBC_SHA", -1, VALL, 0}, + {0x0098, "TLS_DH_RSA_WITH_SEED_CBC_SHA", -1, VALL, 0}, + {0x0099, "TLS_DHE_DSS_WITH_SEED_CBC_SHA", -1, VALL, 0}, + {0x009A, "TLS_DHE_RSA_WITH_SEED_CBC_SHA", -1, VALL, 0}, + {0x009B, "TLS_DH_anon_WITH_SEED_CBC_SHA", -1, VALL, 0}, + {0x009C, "TLS_RSA_WITH_AES_128_GCM_SHA256", 128, VALL, 0}, + {0x009D, "TLS_RSA_WITH_AES_256_GCM_SHA384", 256, VALL, 0}, + {0x009E, "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 128, VALL, 0}, + {0x009F, "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 256, VALL, 0}, + {0x00A0, "TLS_DH_RSA_WITH_AES_128_GCM_SHA256", 128, VALL, 0}, + {0x00A1, "TLS_DH_RSA_WITH_AES_256_GCM_SHA384", 256, VALL, 0}, + {0x00A2, "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 128, VALL, 0}, + {0x00A3, "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 256, VALL, 0}, + {0x00A4, "TLS_DH_DSS_WITH_AES_128_GCM_SHA256", 128, VALL, 0}, + {0x00A5, "TLS_DH_DSS_WITH_AES_256_GCM_SHA384", 256, VALL, 0}, + {0x00A6, "TLS_DH_anon_WITH_AES_128_GCM_SHA256", 128, VALL, 0}, + {0x00A7, "TLS_DH_anon_WITH_AES_256_GCM_SHA384", 256, VALL, 0}, + {0x00A8, "TLS_PSK_WITH_AES_128_GCM_SHA256", 128, VALL, 0}, + {0x00A9, "TLS_PSK_WITH_AES_256_GCM_SHA384", 256, VALL, 0}, + {0x00AA, "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256", 128, VALL, 0}, + {0x00AB, "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384", 256, VALL, 0}, + {0x00AC, "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256", 128, VALL, 0}, + {0x00AD, "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384", 256, VALL, 0}, + {0x00AE, "TLS_PSK_WITH_AES_128_CBC_SHA256", 128, VALL, 0}, + {0x00AF, "TLS_PSK_WITH_AES_256_CBC_SHA384", 256, VALL, 0}, + {0x00B0, "TLS_PSK_WITH_NULL_SHA256", -1, VALL, 0}, + {0x00B1, "TLS_PSK_WITH_NULL_SHA384", -1, VALL, 0}, + {0x00B2, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256", 128, VALL, 0}, + {0x00B3, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384", 256, VALL, 0}, + {0x00B4, "TLS_DHE_PSK_WITH_NULL_SHA256", -1, VALL, 0}, + {0x00B5, "TLS_DHE_PSK_WITH_NULL_SHA384", -1, VALL, 0}, + {0x00B6, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256", 128, VALL, 0}, + {0x00B7, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384", 256, VALL, 0}, + {0x00B8, "TLS_RSA_PSK_WITH_NULL_SHA256", -1, VALL, 0}, + {0x00B9, "TLS_RSA_PSK_WITH_NULL_SHA384", -1, VALL, 0}, + {0x00BA, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256", 128, VALL, 0}, + {0x00BB, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256", 128, VALL, 0}, + {0x00BC, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256", 128, VALL, 0}, + {0x00BD, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256", 128, VALL, 0}, + {0x00BE, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", 128, VALL, 0}, + {0x00BF, "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256", 128, VALL, 0}, + {0x00C0, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256", 256, VALL, 0}, + {0x00C1, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256", 256, VALL, 0}, + {0x00C2, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256", 256, VALL, 0}, + {0x00C3, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256", 256, VALL, 0}, + {0x00C4, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", 256, VALL, 0}, + {0x00C5, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256", 256, VALL, 0}, + {0x00C6, "TLS_SM4_GCM_SM3", 128, VALL, 0}, + {0x00C7, "TLS_SM4_CCM_SM3", 128, VALL, 0}, + {0x1301, "TLS_AES_128_GCM_SHA256", 128, VALL, 0}, + {0x1302, "TLS_AES_256_GCM_SHA384", 256, VALL, 0}, + {0x1303, "TLS_CHACHA20_POLY1305_SHA256", 256, VALL, 0}, + {0x1304, "TLS_AES_128_CCM_SHA256", 128, VALL, 0}, + {0x1305, "TLS_AES_128_CCM_8_SHA256", 128, VALL, 0}, + {0xC001, "TLS_ECDH_ECDSA_WITH_NULL_SHA", -1, VALL, 0}, + {0xC002, "TLS_ECDH_ECDSA_WITH_RC4_128_SHA", 128, VALL, 0}, + {0xC003, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", 112, VALL, 0}, + {0xC004, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", 128, VALL, 0}, + {0xC005, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", 256, VALL, 0}, + {0xC006, "TLS_ECDHE_ECDSA_WITH_NULL_SHA", -1, VALL, 0}, + {0xC007, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", 128, VALL, 0}, + {0xC008, "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", 112, VALL, 0}, + {0xC009, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", 128, VALL, 0}, + {0xC00A, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", 256, VALL, 0}, + {0xC00B, "TLS_ECDH_RSA_WITH_NULL_SHA", -1, VALL, 0}, + {0xC00C, "TLS_ECDH_RSA_WITH_RC4_128_SHA", 128, VALL, 0}, + {0xC00D, "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", 112, VALL, 0}, + {0xC00E, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", 128, VALL, 0}, + {0xC00F, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", 256, VALL, 0}, + {0xC010, "TLS_ECDHE_RSA_WITH_NULL_SHA", -1, VALL, 0}, + {0xC011, "TLS_ECDHE_RSA_WITH_RC4_128_SHA", 128, VALL, 0}, + {0xC012, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", 112, VALL, 0}, + {0xC013, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", 128, VALL, 0}, + {0xC014, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", 256, VALL, 0}, + {0xC015, "TLS_ECDH_anon_WITH_NULL_SHA", -1, VALL, 0}, + {0xC016, "TLS_ECDH_anon_WITH_RC4_128_SHA", 128, VALL, 0}, + {0xC017, "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", 112, VALL, 0}, + {0xC018, "TLS_ECDH_anon_WITH_AES_128_CBC_SHA", 128, VALL, 0}, + {0xC019, "TLS_ECDH_anon_WITH_AES_256_CBC_SHA", 256, VALL, 0}, + {0xC01A, "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", 112, VALL, 0}, + {0xC01B, "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", 112, VALL, 0}, + {0xC01C, "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", 112, VALL, 0}, + {0xC01D, "TLS_SRP_SHA_WITH_AES_128_CBC_SHA", 128, VALL, 0}, + {0xC01E, "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", 128, VALL, 0}, + {0xC01F, "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", 128, VALL, 0}, + {0xC020, "TLS_SRP_SHA_WITH_AES_256_CBC_SHA", 256, VALL, 0}, + {0xC021, "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", 256, VALL, 0}, + {0xC022, "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", 256, VALL, 0}, + {0xC023, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", 128, VALL, 0}, + {0xC024, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", 256, VALL, 0}, + {0xC025, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", 128, VALL, 0}, + {0xC026, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", 256, VALL, 0}, + {0xC027, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", 128, VALL, 0}, + {0xC028, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", 256, VALL, 0}, + {0xC029, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", 128, VALL, 0}, + {0xC02A, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", 256, VALL, 0}, + {0xC02B, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 128, VALL, 0}, + {0xC02C, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 256, VALL, 0}, + {0xC02D, "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 128, VALL, 0}, + {0xC02E, "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 256, VALL, 0}, + {0xC02F, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 128, VALL, 0}, + {0xC030, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 256, VALL, 0}, + {0xC031, "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 128, VALL, 0}, + {0xC032, "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 256, VALL, 0}, + {0xC033, "TLS_ECDHE_PSK_WITH_RC4_128_SHA", 128, VALL, 0}, + {0xC034, "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", 112, VALL, 0}, + {0xC035, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", 128, VALL, 0}, + {0xC036, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", 256, VALL, 0}, + {0xC037, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256", 128, VALL, 0}, + {0xC038, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384", 256, VALL, 0}, + {0xC039, "TLS_ECDHE_PSK_WITH_NULL_SHA", -1, VALL, 0}, + {0xC03A, "TLS_ECDHE_PSK_WITH_NULL_SHA256", -1, VALL, 0}, + {0xC03B, "TLS_ECDHE_PSK_WITH_NULL_SHA384", -1, VALL, 0}, + {0xC03C, "TLS_RSA_WITH_ARIA_128_CBC_SHA256", 128, VALL, 0}, + {0xC03D, "TLS_RSA_WITH_ARIA_256_CBC_SHA384", 256, VALL, 0}, + {0xC03E, "TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256", 128, VALL, 0}, + {0xC03F, "TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384", 256, VALL, 0}, + {0xC040, "TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256", 128, VALL, 0}, + {0xC041, "TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384", 256, VALL, 0}, + {0xC042, "TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256", 128, VALL, 0}, + {0xC043, "TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384", 256, VALL, 0}, + {0xC044, "TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256", 128, VALL, 0}, + {0xC045, "TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384", 256, VALL, 0}, + {0xC046, "TLS_DH_anon_WITH_ARIA_128_CBC_SHA256", 128, VALL, 0}, + {0xC047, "TLS_DH_anon_WITH_ARIA_256_CBC_SHA384", 256, VALL, 0}, + {0xC048, "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256", 128, VALL, 0}, + {0xC049, "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384", 256, VALL, 0}, + {0xC04A, "TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256", 128, VALL, 0}, + {0xC04B, "TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384", 256, VALL, 0}, + {0xC04C, "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256", 128, VALL, 0}, + {0xC04D, "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384", 256, VALL, 0}, + {0xC04E, "TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256", 128, VALL, 0}, + {0xC04F, "TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384", 256, VALL, 0}, + {0xC050, "TLS_RSA_WITH_ARIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC051, "TLS_RSA_WITH_ARIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC052, "TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC053, "TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC054, "TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC055, "TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC056, "TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC057, "TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC058, "TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC059, "TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC05A, "TLS_DH_anon_WITH_ARIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC05B, "TLS_DH_anon_WITH_ARIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC05C, "TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC05D, "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC05E, "TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC05F, "TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC060, "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC061, "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC062, "TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC063, "TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC064, "TLS_PSK_WITH_ARIA_128_CBC_SHA256", 128, VALL, 0}, + {0xC065, "TLS_PSK_WITH_ARIA_256_CBC_SHA384", 256, VALL, 0}, + {0xC066, "TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256", 128, VALL, 0}, + {0xC067, "TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384", 256, VALL, 0}, + {0xC068, "TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256", 128, VALL, 0}, + {0xC069, "TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384", 256, VALL, 0}, + {0xC06A, "TLS_PSK_WITH_ARIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC06B, "TLS_PSK_WITH_ARIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC06C, "TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC06D, "TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC06E, "TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC06F, "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC070, "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256", 128, VALL, 0}, + {0xC071, "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384", 256, VALL, 0}, + {0xC072, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", 128, VALL, 0}, + {0xC073, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", 256, VALL, 0}, + {0xC074, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", 128, VALL, 0}, + {0xC075, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", 256, VALL, 0}, + {0xC076, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", 128, VALL, 0}, + {0xC077, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", 256, VALL, 0}, + {0xC078, "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256", 128, VALL, 0}, + {0xC079, "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384", 256, VALL, 0}, + {0xC07A, "TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC07B, "TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC07C, "TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC07D, "TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC07E, "TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC07F, "TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC080, "TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC081, "TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC082, "TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC083, "TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC084, "TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC085, "TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC086, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC087, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC088, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC089, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC08A, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC08B, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC08C, "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC08D, "TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC08E, "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC08F, "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC090, "TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC091, "TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC092, "TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256", 128, VALL, 0}, + {0xC093, "TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384", 256, VALL, 0}, + {0xC094, "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256", 128, VALL, 0}, + {0xC095, "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384", 256, VALL, 0}, + {0xC096, "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", 128, VALL, 0}, + {0xC097, "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", 256, VALL, 0}, + {0xC098, "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256", 128, VALL, 0}, + {0xC099, "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384", 256, VALL, 0}, + {0xC09A, "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", 128, VALL, 0}, + {0xC09B, "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", 256, VALL, 0}, + {0xC09C, "TLS_RSA_WITH_AES_128_CCM", 128, VALL, 0}, + {0xC09D, "TLS_RSA_WITH_AES_256_CCM", 256, VALL, 0}, + {0xC09E, "TLS_DHE_RSA_WITH_AES_128_CCM", 128, VALL, 0}, + {0xC09F, "TLS_DHE_RSA_WITH_AES_256_CCM", 256, VALL, 0}, + {0xC0A0, "TLS_RSA_WITH_AES_128_CCM_8", 128, VALL, 0}, + {0xC0A1, "TLS_RSA_WITH_AES_256_CCM_8", 256, VALL, 0}, + {0xC0A2, "TLS_DHE_RSA_WITH_AES_128_CCM_8", 128, VALL, 0}, + {0xC0A3, "TLS_DHE_RSA_WITH_AES_256_CCM_8", 256, VALL, 0}, + {0xC0A4, "TLS_PSK_WITH_AES_128_CCM", 128, VALL, 0}, + {0xC0A5, "TLS_PSK_WITH_AES_256_CCM", 256, VALL, 0}, + {0xC0A6, "TLS_DHE_PSK_WITH_AES_128_CCM", 128, VALL, 0}, + {0xC0A7, "TLS_DHE_PSK_WITH_AES_256_CCM", 256, VALL, 0}, + {0xC0A8, "TLS_PSK_WITH_AES_128_CCM_8", 128, VALL, 0}, + {0xC0A9, "TLS_PSK_WITH_AES_256_CCM_8", 256, VALL, 0}, + {0xC0AA, "TLS_PSK_DHE_WITH_AES_128_CCM_8", 128, VALL, 0}, + {0xC0AB, "TLS_PSK_DHE_WITH_AES_256_CCM_8", 256, VALL, 0}, + {0xC0AC, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM", 128, VALL, 0}, + {0xC0AD, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM", 256, VALL, 0}, + {0xC0AE, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8", 128, VALL, 0}, + {0xC0AF, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8", 256, VALL, 0}, + {0xC0B0, "TLS_ECCPWD_WITH_AES_128_GCM_SHA256", 128, VALL, 0}, + {0xC0B1, "TLS_ECCPWD_WITH_AES_256_GCM_SHA384", 256, VALL, 0}, + {0xC0B2, "TLS_ECCPWD_WITH_AES_128_CCM_SHA256", 128, VALL, 0}, + {0xC0B3, "TLS_ECCPWD_WITH_AES_256_CCM_SHA384", 256, VALL, 0}, + {0xC0B4, "TLS_SHA256_SHA256", -1, VALL, 0}, + {0xC0B5, "TLS_SHA384_SHA384", -1, VALL, 0}, + {0xC100, "TLS_GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC", 256, VALL, 0}, + {0xC101, "TLS_GOSTR341112_256_WITH_MAGMA_CTR_OMAC", 256, VALL, 0}, + {0xC102, "TLS_GOSTR341112_256_WITH_28147_CNT_IMIT", 256, VALL, 0}, + {0xCCA8, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", 256, VALL, 0}, + {0xCCA9, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", 256, VALL, 0}, + {0xCCAA, "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", 256, VALL, 0}, + {0xCCAB, "TLS_PSK_WITH_CHACHA20_POLY1305_SHA256", 256, VALL, 0}, + {0xCCAC, "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256", 256, VALL, 0}, + {0xCCAD, "TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256", 256, VALL, 0}, + {0xCCAE, "TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256", 256, VALL, 0}, + {0xD001, "TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256", 128, VALL, 0}, + {0xD002, "TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384", 256, VALL, 0}, + {0xD003, "TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256", 128, VALL, 0}, + {0xD005, "TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256", 128, VALL, 0}, + + /* The ciphers below are reserved for private use (see RFC8446). */ + {0xFF00, "PRIVATE_CIPHER_0", -1, VALL, 0}, + {0xFF01, "PRIVATE_CIPHER_1", -1, VALL, 0}, + {0xFF02, "PRIVATE_CIPHER_2", -1, VALL, 0}, + {0xFF03, "PRIVATE_CIPHER_3", -1, VALL, 0}, + {0xFF04, "PRIVATE_CIPHER_4", -1, VALL, 0}, + {0xFF05, "PRIVATE_CIPHER_5", -1, VALL, 0}, + {0xFF06, "PRIVATE_CIPHER_6", -1, VALL, 0}, + {0xFF07, "PRIVATE_CIPHER_7", -1, VALL, 0}, + {0xFF08, "PRIVATE_CIPHER_8", -1, VALL, 0}, + {0xFF09, "PRIVATE_CIPHER_9", -1, VALL, 0}, + {0xFF0A, "PRIVATE_CIPHER_10", -1, VALL, 0}, + {0xFF0B, "PRIVATE_CIPHER_11", -1, VALL, 0}, + {0xFF0C, "PRIVATE_CIPHER_12", -1, VALL, 0}, + {0xFF0D, "PRIVATE_CIPHER_13", -1, VALL, 0}, + {0xFF0E, "PRIVATE_CIPHER_14", -1, VALL, 0}, + {0xFF0F, "PRIVATE_CIPHER_15", -1, VALL, 0}, + {0xFF10, "PRIVATE_CIPHER_16", -1, VALL, 0}, + {0xFF11, "PRIVATE_CIPHER_17", -1, VALL, 0}, + {0xFF12, "PRIVATE_CIPHER_18", -1, VALL, 0}, + {0xFF13, "PRIVATE_CIPHER_19", -1, VALL, 0}, + {0xFF14, "PRIVATE_CIPHER_20", -1, VALL, 0}, + {0xFF15, "PRIVATE_CIPHER_21", -1, VALL, 0}, + {0xFF16, "PRIVATE_CIPHER_22", -1, VALL, 0}, + {0xFF17, "PRIVATE_CIPHER_23", -1, VALL, 0}, + {0xFF18, "PRIVATE_CIPHER_24", -1, VALL, 0}, + {0xFF19, "PRIVATE_CIPHER_25", -1, VALL, 0}, + {0xFF1A, "PRIVATE_CIPHER_26", -1, VALL, 0}, + {0xFF1B, "PRIVATE_CIPHER_27", -1, VALL, 0}, + {0xFF1C, "PRIVATE_CIPHER_28", -1, VALL, 0}, + {0xFF1D, "PRIVATE_CIPHER_29", -1, VALL, 0}, + {0xFF1E, "PRIVATE_CIPHER_30", -1, VALL, 0}, + {0xFF1F, "PRIVATE_CIPHER_31", -1, VALL, 0}, + {0xFF20, "PRIVATE_CIPHER_32", -1, VALL, 0}, + {0xFF21, "PRIVATE_CIPHER_33", -1, VALL, 0}, + {0xFF22, "PRIVATE_CIPHER_34", -1, VALL, 0}, + {0xFF23, "PRIVATE_CIPHER_35", -1, VALL, 0}, + {0xFF24, "PRIVATE_CIPHER_36", -1, VALL, 0}, + {0xFF25, "PRIVATE_CIPHER_37", -1, VALL, 0}, + {0xFF26, "PRIVATE_CIPHER_38", -1, VALL, 0}, + {0xFF27, "PRIVATE_CIPHER_39", -1, VALL, 0}, + {0xFF28, "PRIVATE_CIPHER_40", -1, VALL, 0}, + {0xFF29, "PRIVATE_CIPHER_41", -1, VALL, 0}, + {0xFF2A, "PRIVATE_CIPHER_42", -1, VALL, 0}, + {0xFF2B, "PRIVATE_CIPHER_43", -1, VALL, 0}, + {0xFF2C, "PRIVATE_CIPHER_44", -1, VALL, 0}, + {0xFF2D, "PRIVATE_CIPHER_45", -1, VALL, 0}, + {0xFF2E, "PRIVATE_CIPHER_46", -1, VALL, 0}, + {0xFF2F, "PRIVATE_CIPHER_47", -1, VALL, 0}, + {0xFF30, "PRIVATE_CIPHER_48", -1, VALL, 0}, + {0xFF31, "PRIVATE_CIPHER_49", -1, VALL, 0}, + {0xFF32, "PRIVATE_CIPHER_50", -1, VALL, 0}, + {0xFF33, "PRIVATE_CIPHER_51", -1, VALL, 0}, + {0xFF34, "PRIVATE_CIPHER_52", -1, VALL, 0}, + {0xFF35, "PRIVATE_CIPHER_53", -1, VALL, 0}, + {0xFF36, "PRIVATE_CIPHER_54", -1, VALL, 0}, + {0xFF37, "PRIVATE_CIPHER_55", -1, VALL, 0}, + {0xFF38, "PRIVATE_CIPHER_56", -1, VALL, 0}, + {0xFF39, "PRIVATE_CIPHER_57", -1, VALL, 0}, + {0xFF3A, "PRIVATE_CIPHER_58", -1, VALL, 0}, + {0xFF3B, "PRIVATE_CIPHER_59", -1, VALL, 0}, + {0xFF3C, "PRIVATE_CIPHER_60", -1, VALL, 0}, + {0xFF3D, "PRIVATE_CIPHER_61", -1, VALL, 0}, + {0xFF3E, "PRIVATE_CIPHER_62", -1, VALL, 0}, + {0xFF3F, "PRIVATE_CIPHER_63", -1, VALL, 0}, + {0xFF40, "PRIVATE_CIPHER_64", -1, VALL, 0}, + {0xFF41, "PRIVATE_CIPHER_65", -1, VALL, 0}, + {0xFF42, "PRIVATE_CIPHER_66", -1, VALL, 0}, + {0xFF43, "PRIVATE_CIPHER_67", -1, VALL, 0}, + {0xFF44, "PRIVATE_CIPHER_68", -1, VALL, 0}, + {0xFF45, "PRIVATE_CIPHER_69", -1, VALL, 0}, + {0xFF46, "PRIVATE_CIPHER_70", -1, VALL, 0}, + {0xFF47, "PRIVATE_CIPHER_71", -1, VALL, 0}, + {0xFF48, "PRIVATE_CIPHER_72", -1, VALL, 0}, + {0xFF49, "PRIVATE_CIPHER_73", -1, VALL, 0}, + {0xFF4A, "PRIVATE_CIPHER_74", -1, VALL, 0}, + {0xFF4B, "PRIVATE_CIPHER_75", -1, VALL, 0}, + {0xFF4C, "PRIVATE_CIPHER_76", -1, VALL, 0}, + {0xFF4D, "PRIVATE_CIPHER_77", -1, VALL, 0}, + {0xFF4E, "PRIVATE_CIPHER_78", -1, VALL, 0}, + {0xFF4F, "PRIVATE_CIPHER_79", -1, VALL, 0}, + {0xFF50, "PRIVATE_CIPHER_80", -1, VALL, 0}, + {0xFF51, "PRIVATE_CIPHER_81", -1, VALL, 0}, + {0xFF52, "PRIVATE_CIPHER_82", -1, VALL, 0}, + {0xFF53, "PRIVATE_CIPHER_83", -1, VALL, 0}, + {0xFF54, "PRIVATE_CIPHER_84", -1, VALL, 0}, + {0xFF55, "PRIVATE_CIPHER_85", -1, VALL, 0}, + {0xFF56, "PRIVATE_CIPHER_86", -1, VALL, 0}, + {0xFF57, "PRIVATE_CIPHER_87", -1, VALL, 0}, + {0xFF58, "PRIVATE_CIPHER_88", -1, VALL, 0}, + {0xFF59, "PRIVATE_CIPHER_89", -1, VALL, 0}, + {0xFF5A, "PRIVATE_CIPHER_90", -1, VALL, 0}, + {0xFF5B, "PRIVATE_CIPHER_91", -1, VALL, 0}, + {0xFF5C, "PRIVATE_CIPHER_92", -1, VALL, 0}, + {0xFF5D, "PRIVATE_CIPHER_93", -1, VALL, 0}, + {0xFF5E, "PRIVATE_CIPHER_94", -1, VALL, 0}, + {0xFF5F, "PRIVATE_CIPHER_95", -1, VALL, 0}, + {0xFF60, "PRIVATE_CIPHER_96", -1, VALL, 0}, + {0xFF61, "PRIVATE_CIPHER_97", -1, VALL, 0}, + {0xFF62, "PRIVATE_CIPHER_98", -1, VALL, 0}, + {0xFF63, "PRIVATE_CIPHER_99", -1, VALL, 0}, + {0xFF64, "PRIVATE_CIPHER_100", -1, VALL, 0}, + {0xFF65, "PRIVATE_CIPHER_101", -1, VALL, 0}, + {0xFF66, "PRIVATE_CIPHER_102", -1, VALL, 0}, + {0xFF67, "PRIVATE_CIPHER_103", -1, VALL, 0}, + {0xFF68, "PRIVATE_CIPHER_104", -1, VALL, 0}, + {0xFF69, "PRIVATE_CIPHER_105", -1, VALL, 0}, + {0xFF6A, "PRIVATE_CIPHER_106", -1, VALL, 0}, + {0xFF6B, "PRIVATE_CIPHER_107", -1, VALL, 0}, + {0xFF6C, "PRIVATE_CIPHER_108", -1, VALL, 0}, + {0xFF6D, "PRIVATE_CIPHER_109", -1, VALL, 0}, + {0xFF6E, "PRIVATE_CIPHER_110", -1, VALL, 0}, + {0xFF6F, "PRIVATE_CIPHER_111", -1, VALL, 0}, + {0xFF70, "PRIVATE_CIPHER_112", -1, VALL, 0}, + {0xFF71, "PRIVATE_CIPHER_113", -1, VALL, 0}, + {0xFF72, "PRIVATE_CIPHER_114", -1, VALL, 0}, + {0xFF73, "PRIVATE_CIPHER_115", -1, VALL, 0}, + {0xFF74, "PRIVATE_CIPHER_116", -1, VALL, 0}, + {0xFF75, "PRIVATE_CIPHER_117", -1, VALL, 0}, + {0xFF76, "PRIVATE_CIPHER_118", -1, VALL, 0}, + {0xFF77, "PRIVATE_CIPHER_119", -1, VALL, 0}, + {0xFF78, "PRIVATE_CIPHER_120", -1, VALL, 0}, + {0xFF79, "PRIVATE_CIPHER_121", -1, VALL, 0}, + {0xFF7A, "PRIVATE_CIPHER_122", -1, VALL, 0}, + {0xFF7B, "PRIVATE_CIPHER_123", -1, VALL, 0}, + {0xFF7C, "PRIVATE_CIPHER_124", -1, VALL, 0}, + {0xFF7D, "PRIVATE_CIPHER_125", -1, VALL, 0}, + {0xFF7E, "PRIVATE_CIPHER_126", -1, VALL, 0}, + {0xFF7F, "PRIVATE_CIPHER_127", -1, VALL, 0}, + {0xFF80, "PRIVATE_CIPHER_128", -1, VALL, 0}, + {0xFF81, "PRIVATE_CIPHER_129", -1, VALL, 0}, + {0xFF82, "PRIVATE_CIPHER_130", -1, VALL, 0}, + {0xFF83, "PRIVATE_CIPHER_131", -1, VALL, 0}, + {0xFF84, "PRIVATE_CIPHER_132", -1, VALL, 0}, + {0xFF85, "PRIVATE_CIPHER_133", -1, VALL, 0}, + {0xFF86, "PRIVATE_CIPHER_134", -1, VALL, 0}, + {0xFF87, "PRIVATE_CIPHER_135", -1, VALL, 0}, + {0xFF88, "PRIVATE_CIPHER_136", -1, VALL, 0}, + {0xFF89, "PRIVATE_CIPHER_137", -1, VALL, 0}, + {0xFF8A, "PRIVATE_CIPHER_138", -1, VALL, 0}, + {0xFF8B, "PRIVATE_CIPHER_139", -1, VALL, 0}, + {0xFF8C, "PRIVATE_CIPHER_140", -1, VALL, 0}, + {0xFF8D, "PRIVATE_CIPHER_141", -1, VALL, 0}, + {0xFF8E, "PRIVATE_CIPHER_142", -1, VALL, 0}, + {0xFF8F, "PRIVATE_CIPHER_143", -1, VALL, 0}, + {0xFF90, "PRIVATE_CIPHER_144", -1, VALL, 0}, + {0xFF91, "PRIVATE_CIPHER_145", -1, VALL, 0}, + {0xFF92, "PRIVATE_CIPHER_146", -1, VALL, 0}, + {0xFF93, "PRIVATE_CIPHER_147", -1, VALL, 0}, + {0xFF94, "PRIVATE_CIPHER_148", -1, VALL, 0}, + {0xFF95, "PRIVATE_CIPHER_149", -1, VALL, 0}, + {0xFF96, "PRIVATE_CIPHER_150", -1, VALL, 0}, + {0xFF97, "PRIVATE_CIPHER_151", -1, VALL, 0}, + {0xFF98, "PRIVATE_CIPHER_152", -1, VALL, 0}, + {0xFF99, "PRIVATE_CIPHER_153", -1, VALL, 0}, + {0xFF9A, "PRIVATE_CIPHER_154", -1, VALL, 0}, + {0xFF9B, "PRIVATE_CIPHER_155", -1, VALL, 0}, + {0xFF9C, "PRIVATE_CIPHER_156", -1, VALL, 0}, + {0xFF9D, "PRIVATE_CIPHER_157", -1, VALL, 0}, + {0xFF9E, "PRIVATE_CIPHER_158", -1, VALL, 0}, + {0xFF9F, "PRIVATE_CIPHER_159", -1, VALL, 0}, + {0xFFA0, "PRIVATE_CIPHER_160", -1, VALL, 0}, + {0xFFA1, "PRIVATE_CIPHER_161", -1, VALL, 0}, + {0xFFA2, "PRIVATE_CIPHER_162", -1, VALL, 0}, + {0xFFA3, "PRIVATE_CIPHER_163", -1, VALL, 0}, + {0xFFA4, "PRIVATE_CIPHER_164", -1, VALL, 0}, + {0xFFA5, "PRIVATE_CIPHER_165", -1, VALL, 0}, + {0xFFA6, "PRIVATE_CIPHER_166", -1, VALL, 0}, + {0xFFA7, "PRIVATE_CIPHER_167", -1, VALL, 0}, + {0xFFA8, "PRIVATE_CIPHER_168", -1, VALL, 0}, + {0xFFA9, "PRIVATE_CIPHER_169", -1, VALL, 0}, + {0xFFAA, "PRIVATE_CIPHER_170", -1, VALL, 0}, + {0xFFAB, "PRIVATE_CIPHER_171", -1, VALL, 0}, + {0xFFAC, "PRIVATE_CIPHER_172", -1, VALL, 0}, + {0xFFAD, "PRIVATE_CIPHER_173", -1, VALL, 0}, + {0xFFAE, "PRIVATE_CIPHER_174", -1, VALL, 0}, + {0xFFAF, "PRIVATE_CIPHER_175", -1, VALL, 0}, + {0xFFB0, "PRIVATE_CIPHER_176", -1, VALL, 0}, + {0xFFB1, "PRIVATE_CIPHER_177", -1, VALL, 0}, + {0xFFB2, "PRIVATE_CIPHER_178", -1, VALL, 0}, + {0xFFB3, "PRIVATE_CIPHER_179", -1, VALL, 0}, + {0xFFB4, "PRIVATE_CIPHER_180", -1, VALL, 0}, + {0xFFB5, "PRIVATE_CIPHER_181", -1, VALL, 0}, + {0xFFB6, "PRIVATE_CIPHER_182", -1, VALL, 0}, + {0xFFB7, "PRIVATE_CIPHER_183", -1, VALL, 0}, + {0xFFB8, "PRIVATE_CIPHER_184", -1, VALL, 0}, + {0xFFB9, "PRIVATE_CIPHER_185", -1, VALL, 0}, + {0xFFBA, "PRIVATE_CIPHER_186", -1, VALL, 0}, + {0xFFBB, "PRIVATE_CIPHER_187", -1, VALL, 0}, + {0xFFBC, "PRIVATE_CIPHER_188", -1, VALL, 0}, + {0xFFBD, "PRIVATE_CIPHER_189", -1, VALL, 0}, + {0xFFBE, "PRIVATE_CIPHER_190", -1, VALL, 0}, + {0xFFBF, "PRIVATE_CIPHER_191", -1, VALL, 0}, + {0xFFC0, "PRIVATE_CIPHER_192", -1, VALL, 0}, + {0xFFC1, "PRIVATE_CIPHER_193", -1, VALL, 0}, + {0xFFC2, "PRIVATE_CIPHER_194", -1, VALL, 0}, + {0xFFC3, "PRIVATE_CIPHER_195", -1, VALL, 0}, + {0xFFC4, "PRIVATE_CIPHER_196", -1, VALL, 0}, + {0xFFC5, "PRIVATE_CIPHER_197", -1, VALL, 0}, + {0xFFC6, "PRIVATE_CIPHER_198", -1, VALL, 0}, + {0xFFC7, "PRIVATE_CIPHER_199", -1, VALL, 0}, + {0xFFC8, "PRIVATE_CIPHER_200", -1, VALL, 0}, + {0xFFC9, "PRIVATE_CIPHER_201", -1, VALL, 0}, + {0xFFCA, "PRIVATE_CIPHER_202", -1, VALL, 0}, + {0xFFCB, "PRIVATE_CIPHER_203", -1, VALL, 0}, + {0xFFCC, "PRIVATE_CIPHER_204", -1, VALL, 0}, + {0xFFCD, "PRIVATE_CIPHER_205", -1, VALL, 0}, + {0xFFCE, "PRIVATE_CIPHER_206", -1, VALL, 0}, + {0xFFCF, "PRIVATE_CIPHER_207", -1, VALL, 0}, + {0xFFD0, "PRIVATE_CIPHER_208", -1, VALL, 0}, + {0xFFD1, "PRIVATE_CIPHER_209", -1, VALL, 0}, + {0xFFD2, "PRIVATE_CIPHER_210", -1, VALL, 0}, + {0xFFD3, "PRIVATE_CIPHER_211", -1, VALL, 0}, + {0xFFD4, "PRIVATE_CIPHER_212", -1, VALL, 0}, + {0xFFD5, "PRIVATE_CIPHER_213", -1, VALL, 0}, + {0xFFD6, "PRIVATE_CIPHER_214", -1, VALL, 0}, + {0xFFD7, "PRIVATE_CIPHER_215", -1, VALL, 0}, + {0xFFD8, "PRIVATE_CIPHER_216", -1, VALL, 0}, + {0xFFD9, "PRIVATE_CIPHER_217", -1, VALL, 0}, + {0xFFDA, "PRIVATE_CIPHER_218", -1, VALL, 0}, + {0xFFDB, "PRIVATE_CIPHER_219", -1, VALL, 0}, + {0xFFDC, "PRIVATE_CIPHER_220", -1, VALL, 0}, + {0xFFDD, "PRIVATE_CIPHER_221", -1, VALL, 0}, + {0xFFDE, "PRIVATE_CIPHER_222", -1, VALL, 0}, + {0xFFDF, "PRIVATE_CIPHER_223", -1, VALL, 0}, + {0xFFE0, "PRIVATE_CIPHER_224", -1, VALL, 0}, + {0xFFE1, "PRIVATE_CIPHER_225", -1, VALL, 0}, + {0xFFE2, "PRIVATE_CIPHER_226", -1, VALL, 0}, + {0xFFE3, "PRIVATE_CIPHER_227", -1, VALL, 0}, + {0xFFE4, "PRIVATE_CIPHER_228", -1, VALL, 0}, + {0xFFE5, "PRIVATE_CIPHER_229", -1, VALL, 0}, + {0xFFE6, "PRIVATE_CIPHER_230", -1, VALL, 0}, + {0xFFE7, "PRIVATE_CIPHER_231", -1, VALL, 0}, + {0xFFE8, "PRIVATE_CIPHER_232", -1, VALL, 0}, + {0xFFE9, "PRIVATE_CIPHER_233", -1, VALL, 0}, + {0xFFEA, "PRIVATE_CIPHER_234", -1, VALL, 0}, + {0xFFEB, "PRIVATE_CIPHER_235", -1, VALL, 0}, + {0xFFEC, "PRIVATE_CIPHER_236", -1, VALL, 0}, + {0xFFED, "PRIVATE_CIPHER_237", -1, VALL, 0}, + {0xFFEE, "PRIVATE_CIPHER_238", -1, VALL, 0}, + {0xFFEF, "PRIVATE_CIPHER_239", -1, VALL, 0}, + {0xFFF0, "PRIVATE_CIPHER_240", -1, VALL, 0}, + {0xFFF1, "PRIVATE_CIPHER_241", -1, VALL, 0}, + {0xFFF2, "PRIVATE_CIPHER_242", -1, VALL, 0}, + {0xFFF3, "PRIVATE_CIPHER_243", -1, VALL, 0}, + {0xFFF4, "PRIVATE_CIPHER_244", -1, VALL, 0}, + {0xFFF5, "PRIVATE_CIPHER_245", -1, VALL, 0}, + {0xFFF6, "PRIVATE_CIPHER_246", -1, VALL, 0}, + {0xFFF7, "PRIVATE_CIPHER_247", -1, VALL, 0}, + {0xFFF8, "PRIVATE_CIPHER_248", -1, VALL, 0}, + {0xFFF9, "PRIVATE_CIPHER_249", -1, VALL, 0}, + {0xFFFA, "PRIVATE_CIPHER_250", -1, VALL, 0}, + {0xFFFB, "PRIVATE_CIPHER_251", -1, VALL, 0}, + {0xFFFC, "PRIVATE_CIPHER_252", -1, VALL, 0}, + {0xFFFD, "PRIVATE_CIPHER_253", -1, VALL, 0}, + {0xFFFE, "PRIVATE_CIPHER_254", -1, VALL, 0}, + {0xFFFF, "PRIVATE_CIPHER_255", -1, VALL, 0}, +}; + +#endif diff --git a/sslscan.c b/sslscan.c index 4e9d53b..36aae48 100644 --- a/sslscan.c +++ b/sslscan.c @@ -1571,29 +1571,115 @@ char *cipherRemove(char *str, const char *sub) { return str; } +/* Outputs an accepted cipher to the console and XML file. */ +void outputCipher(struct sslCheckOptions *options, SSL *ssl, const char *cleanSslMethod, uint32_t cipherid, const char *ciphername, int cipherbits, int cipher_accepted, unsigned int milliseconds_elapsed, char *http_code) { + char hexCipherId[8] = {0}; + unsigned int tempInt = 0; + + + printf_xml(" cipherstring, CIPHERSUITE_LIST_ALL) && strcmp(options->cipherstring, TLSV13_CIPHERSUITES)) { + printf_xml("accepted\""); + printf("Accepted "); + } + else { + printf_xml("preferred\""); + printf("%sPreferred%s ", COL_GREEN, RESET); + } + + if (options->http == true) { + printf("%s", http_code); + printf_xml(" http=\"%s\"", http_code); + } + + printf_xml(" sslversion=\"%s\"", cleanSslMethod); + if (strcmp(cleanSslMethod, "TLSv1.0") == 0) { + printf("%sTLSv1.0%s ", COL_YELLOW, RESET); + } else + printf("%s ", cleanSslMethod); + + if (cipherbits < 10) + tempInt = 2; + else if (cipherbits < 100) + tempInt = 1; + + if (cipherbits == -1) { /* When missing ciphers are tested, and we don't have a reasonable guess. */ + printf("%s??%s bits ", COL_YELLOW, RESET); + } else if (cipherbits == 0) { + printf("%s%d%s bits ", COL_RED_BG, cipherbits, RESET); + } else if (cipherbits >= 112) { + printf("%s%d%s bits ", COL_GREEN, cipherbits, RESET); + } else if (cipherbits > 56) { + printf("%s%d%s bits ", COL_YELLOW, cipherbits, RESET); + } else + printf("%s%d%s bits ", COL_RED, cipherbits, RESET); + + while (tempInt != 0) { + tempInt--; + printf(" "); + } + + snprintf(hexCipherId, sizeof(hexCipherId) - 1, "0x%04X", cipherid); + if (options->showCipherIds == true) + printf("%8s ", hexCipherId); + + printf_xml(" bits=\"%d\" cipher=\"%s\" id=\"%s\"", cipherbits, ciphername, hexCipherId); + if (strstr(ciphername, "NULL")) { + printf("%s%-29s%s", COL_RED_BG, ciphername, RESET); + } else if (strstr(ciphername, "ADH") || strstr(ciphername, "AECDH") || strstr(ciphername, "_anon_")) { + printf("%s%-29s%s", COL_PURPLE, ciphername, RESET); + } else if (strstr(ciphername, "EXP")) { + printf("%s%-29s%s", COL_RED, ciphername, RESET); + } else if (strstr(ciphername, "RC4") || strstr(ciphername, "DES")) { + printf("%s%-29s%s", COL_YELLOW, ciphername, RESET); + } else if ((strstr(ciphername, "CHACHA20") || (strstr(ciphername, "GCM"))) && strstr(ciphername, "DHE")) { + printf("%s%-29s%s", COL_GREEN, ciphername, RESET); + } else { + printf("%-29s", ciphername); + } + + if ((options->cipher_details == true) && (ssl != NULL)) + ssl_print_tmp_key(options, ssl); + + // Timing + if (options->showTimes) { + printf(" %s%ums%s", COL_GREY, milliseconds_elapsed, RESET); + printf_xml(" time=\"%u\"", milliseconds_elapsed); + } + + printf("\n"); + } + + printf_xml(" />\n"); +} + // Test a cipher... int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) { // Variables... - int cipherStatus; + int cipherStatus = 0; int status = true; int socketDescriptor = 0; SSL *ssl = NULL; - BIO *cipherConnectionBio; - BIO *stdoutBIO = NULL; - int tempInt; - char requestBuffer[200]; - char buffer[50]; - char hexCipherId[10]; + BIO *cipherConnectionBio = NULL; + char requestBuffer[256]; + char buffer[64]; + char http_code[64]; int resultSize = 0; - int cipherbits; - uint32_t cipherid; - const SSL_CIPHER *sslCipherPointer; + int cipherbits = -1; + uint32_t cipherid = 0; + const SSL_CIPHER *sslCipherPointer = NULL; const char *cleanSslMethod = printableSslMethod(sslMethod); - const char *ciphername; - struct timeval tval_start, tval_end, tval_elapsed; + const char *ciphername = NULL; + struct timeval tval_start = {0}; + unsigned int milliseconds_elapsed = 0; + memset(requestBuffer, 0, sizeof(requestBuffer)); + memset(buffer, 0, sizeof(buffer)); + memset(http_code, 0, sizeof(http_code)); + if (options->showTimes) { gettimeofday(&tval_start, NULL); @@ -1607,7 +1693,6 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) { // Create SSL object... ssl = new_SSL(options->ctx); - if (ssl != NULL) { // Connect socket and BIO @@ -1616,10 +1701,8 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) // Connect SSL and BIO SSL_set_bio(ssl, cipherConnectionBio, cipherConnectionBio); -#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT) // This enables TLS SNI SSL_set_tlsext_host_name (ssl, options->sniname); -#endif // Connect SSL over socket cipherStatus = SSL_connect(ssl); @@ -1640,31 +1723,11 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) cipherid = SSL_CIPHER_get_id(sslCipherPointer); cipherid = cipherid & 0x00ffffff; // remove first byte which is the version (0x03 for TLSv1/SSLv3) - // Show Cipher Status - printf_xml(" cipherstring, CIPHERSUITE_LIST_ALL) && strcmp(options->cipherstring, TLSV13_CIPHERSUITES)) - { - printf_xml("accepted\""); - printf("Accepted "); - } - else - { - printf_xml("preferred\""); - printf("%sPreferred%s ", COL_GREEN, RESET); - } if (options->http == true) { - - // Stdout BIO... - if (!xml_to_stdout) { - stdoutBIO = BIO_new(BIO_s_file()); - BIO_set_fp(stdoutBIO, stdout, BIO_NOCLOSE); - } - // Create request buffer... - memset(requestBuffer, 0, sizeof(requestBuffer)); snprintf(requestBuffer, sizeof(requestBuffer) - 1, "GET / HTTP/1.0\r\nUser-Agent: SSLScan\r\nHost: %s\r\n\r\n", options->host); // HTTP Get... @@ -1678,133 +1741,35 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) { } buffer[loop] = 0; - // Output HTTP code... - printf("%s", buffer + 9); + strncpy(http_code, buffer + 9, sizeof(http_code) - 1); loop = strlen(buffer + 9); while (loop < 17) { loop++; - printf(" "); + strncat(http_code, " ", sizeof(http_code) - 1); } - printf_xml(" http=\"%s\"", buffer + 9); + } else { // Output HTTP code... - printf(" "); + strncpy(http_code, " ", sizeof(http_code) - 1); } } } - printf_xml(" sslversion=\"%s\"", cleanSslMethod); -#ifndef OPENSSL_NO_SSL2 - if (strcmp(cleanSslMethod, "SSLv2") == 0) - { - printf("%sSSLv2%s ", COL_RED, RESET); - } - else -#endif -#ifndef OPENSSL_NO_SSL3 - if (strcmp(cleanSslMethod, "SSLv3") == 0) - { - printf("%sSSLv3%s ", COL_RED, RESET); - } - else -#endif - if (strcmp(cleanSslMethod, "TLSv1.0") == 0) - { - printf("%sTLSv1.0%s ", COL_YELLOW, RESET); - } -#if OPENSSL_VERSION_NUMBER >= 0x10001000L - else - { - printf("%s ", cleanSslMethod); - } -#endif - if (cipherbits < 10) - tempInt = 2; - else if (cipherbits < 100) - tempInt = 1; - else - tempInt = 0; - if (cipherbits == 0) - { - printf("%s%d%s bits ", COL_RED_BG, cipherbits, RESET); - } - else if (cipherbits >= 112) - { - printf("%s%d%s bits ", COL_GREEN, cipherbits, RESET); - } - else if (cipherbits > 56) - { - printf("%s%d%s bits ", COL_YELLOW, cipherbits, RESET); - } - else - { - printf("%s%d%s bits ", COL_RED, cipherbits, RESET); - } - while (tempInt != 0) - { - tempInt--; - printf(" "); - } - sprintf(hexCipherId, "0x%X", cipherid); + ciphername = SSL_CIPHER_get_name(sslCipherPointer); - if (options->showCipherIds == true) - { - printf("%8s ", hexCipherId); - } - - ciphername=SSL_CIPHER_get_name(sslCipherPointer); - - printf_xml(" bits=\"%d\" cipher=\"%s\" id=\"%s\"", cipherbits, ciphername, hexCipherId); - if (strstr(ciphername, "NULL")) - { - printf("%s%-29s%s", COL_RED_BG, ciphername, RESET); - } - else if (strstr(ciphername, "ADH") || strstr(ciphername, "AECDH")) - { - printf("%s%-29s%s", COL_PURPLE, ciphername, RESET); - } - else if (strstr(ciphername, "EXP") -#ifndef OPENSSL_NO_SSL3 - || (strcmp(cleanSslMethod, "SSLv3") == 0 && !strstr(ciphername, "RC4")) -#endif - ) - { - printf("%s%-29s%s", COL_RED, ciphername, RESET); - } - else if (strstr(ciphername, "RC4") || strstr(ciphername, "DES")) - { - printf("%s%-29s%s", COL_YELLOW, ciphername, RESET); - } - else if ((strstr(ciphername, "CHACHA20") || (strstr(ciphername, "GCM"))) - && strstr(ciphername, "DHE")) - { - printf("%s%-29s%s", COL_GREEN, ciphername, RESET); - } - else - { - printf("%-29s", ciphername); - } + // Timing + if (options->showTimes) { + struct timeval tval_end = {0}, tval_elapsed = {0}; - if (options->cipher_details == true) - { - ssl_print_tmp_key(options, ssl); - } - // Timing - if (options->showTimes) - { - int msec; - gettimeofday(&tval_end, NULL); - timersub(&tval_end, &tval_start, &tval_elapsed); - msec = tval_elapsed.tv_sec * 1000 + (int)tval_elapsed.tv_usec/1000; - printf("%s %dms%s", COL_GREY, msec, RESET); - printf_xml(" time=\"%d\"", msec); - } + gettimeofday(&tval_end, NULL); + timersub(&tval_end, &tval_start, &tval_elapsed); + milliseconds_elapsed = tval_elapsed.tv_sec * 1000 + (int)tval_elapsed.tv_usec / 1000; + } - printf("\n"); - printf_xml(" />\n"); + outputCipher(options, ssl, cleanSslMethod, cipherid, ciphername, cipherbits, (cipherStatus == 1), milliseconds_elapsed, http_code); // Disconnect SSL over socket if (cipherStatus == 1) @@ -1816,7 +1781,7 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) } else { - strncat(options->cipherstring, ":!", 2); + strncat(options->cipherstring, ":!", 2); strncat(options->cipherstring, usedcipher, strlen(usedcipher)); } SSL_shutdown(ssl); @@ -1837,7 +1802,7 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) } // Disconnect from host - close(socketDescriptor); + CLOSE(socketDescriptor); } // Could not connect @@ -3319,6 +3284,17 @@ int testProtocolCiphers(struct sslCheckOptions *options, const SSL_METHOD *sslMe return false; } } + + /* Test the missing ciphersuites. */ + if (sslMethod != TLSv1_3_client_method()) { + int version = 0; + if (sslMethod == TLSv1_1_client_method()) + version = 1; + else if (sslMethod == TLSv1_2_client_method()) + version = 2; + + testMissingCiphers(options, version); + } return true; } @@ -3377,15 +3353,20 @@ int testHost(struct sslCheckOptions *options) populateCipherList(options, TLSv1_client_method()); break; } - printf("\n %sSupported Client Cipher(s):%s\n", COL_BLUE, RESET); + printf("\n %sOpenSSL-Supported Client Cipher(s):%s\n", COL_BLUE, RESET); sslCipherPointer = options->ciphers; while ((sslCipherPointer != 0) && (status == true)) { printf(" %s\n",sslCipherPointer->name); - printf_xml(" \n", sslCipherPointer->name); + printf_xml(" \n", sslCipherPointer->name); sslCipherPointer = sslCipherPointer->next; } + printf("\n %sDirectly-Supported Client Cipher(s):%s\n", COL_BLUE, RESET); + for (int i = 0; i < (sizeof(missing_ciphersuites) / sizeof(struct missing_ciphersuite)); i++) { + printf(" %s\n", missing_ciphersuites[i].protocol_name); + printf_xml(" \n", missing_ciphersuites[i].protocol_name); + } printf("\n"); } if (status == true && options->fallback ) @@ -3980,6 +3961,9 @@ int main(int argc, char *argv[]) fprintf(options.xmlOutput, "\n\n", VERSION); } + // Build the list of ciphers missing from OpenSSL. + findMissingCiphers(); + switch (mode) { case mode_version: @@ -4380,6 +4364,409 @@ int runSSLv3Test(struct sslCheckOptions *options) { return ret; } +/* Compares the list of supported ciphersuites by OpenSSL with the complete list of ciphersuites from IANA. Marks the matches so they are not re-tested again later. */ +void findMissingCiphers() { + STACK_OF(SSL_CIPHER) *cipherList = NULL; + const SSL_CIPHER *cipher = NULL; + unsigned int tls_version = 0; + uint32_t id = 0; + const SSL_METHOD *sslMethods[] = { TLSv1_client_method(), TLSv1_1_client_method(), TLSv1_2_client_method() }; + unsigned int tls_versions[] = { V1_0, V1_1, V1_2 }; + + /* For each TLS version (not including v1.3)... */ + for (int m = 0; m < (sizeof(sslMethods) / sizeof(const SSL_METHOD *)); m++) { + tls_version = tls_versions[m]; + SSL_CTX *ctx = new_CTX(sslMethods[m]); + SSL_CTX_set_cipher_list(ctx, CIPHERSUITE_LIST_ALL); + cipherList = SSL_CTX_get_ciphers(ctx); + + /* Loop through all OpenSSL ciphers... */ + for (int i = 0; i < sk_SSL_CIPHER_num(cipherList); i++) { + cipher = sk_SSL_CIPHER_value(cipherList, i); + id = SSL_CIPHER_get_protocol_id(cipher); + + /* Using the cipher ID, find the match in the IANA list. */ + for (int j = 0; j < (sizeof(missing_ciphersuites) / sizeof(struct missing_ciphersuite)); j++) { + if ((missing_ciphersuites[j].id == id) && (missing_ciphersuites[j].check_tls_versions & tls_version)) { + /* Turn off the flag for this version of TLS. */ + missing_ciphersuites[j].check_tls_versions &= ~tls_version; + } + } + } + + FREE_CTX(ctx); + } +} + +/* Appends an array of bytes (in 'bytes') of length 'bytes_len' to an array (in 'buffer'). The current size of 'buffer' is given in 'buf_size'. The current number of bytes used in the buffer is given in 'buf_len'. If the caller tries to append bytes that the current buffer cannot hold, the buffer will be automatically re-sized and the bytes are safely appended. The extended buffer region is zeroed. */ +#define OVERFLOW_MESSAGE "Cannot lengthen buffer without overflowing length!\n" +void buffer_append_bytes(unsigned char **buffer, size_t *buf_size, size_t *buf_len, unsigned char *bytes, size_t bytes_len) { + size_t new_len = *buf_len + bytes_len; + + if (buffer == NULL) + return; + + /* Ensure that the new length does not cause an integer overflow. */ + if ((new_len < *buf_len) || (new_len < bytes_len)) { + fprintf(stderr, OVERFLOW_MESSAGE); + exit(-1); + } + + /* If the buffer needs re-sizing... */ + if (new_len > *buf_size) { + + /* Double the size of the buffer until it is larger than what we need right now. */ + while (new_len > *buf_size) { + /* Ensure we don't overflow the length. */ + if ((size_t)(*buf_len * 2) < *buf_len) { + fprintf(stderr, OVERFLOW_MESSAGE); + exit(-1); + } + *buf_size = *buf_size * 2; + } + + /* Extend the buffer's size. */ + *buffer = realloc(*buffer, *buf_size); + if (*buffer == NULL) { + fprintf(stderr, "Failed to resize buffer.\n"); + exit(-1); + } + + /* Zero out the extended buffer region; leave the existing bytes intact. */ + memset(*buffer + *buf_len, 0, *buf_size - *buf_len); + } + + /* Copy the new bytes into the buffer right after the existing bytes. */ + memcpy(*buffer + *buf_len, bytes, bytes_len); + + /* Update the number of used bytes in the buffer. */ + *buf_len = new_len; +} + +/* Convert an unsigned short to network-order, then append it to the buffer. See documentation for buffer_append_bytes() for description of other arguments. */ +void buffer_append_ushort(unsigned char **buffer, size_t *buf_size, size_t *buf_len, unsigned short s) { + unsigned short network_short = htons(s); + buffer_append_bytes(buffer, buf_size, buf_len, (unsigned char *)&network_short, sizeof(unsigned short)); +} + +/* Append a uint32_t to the buffer. See documentation for buffer_append_bytes() for description of other arguments. */ +void buffer_append_uint32_t(unsigned char **buffer, size_t *buf_size, size_t *buf_len, uint32_t i) { + buffer_append_bytes(buffer, buf_size, buf_len, (unsigned char *)&i, sizeof(uint32_t)); +} + +/* Sets the 'ciphersuite_list' arg to a buffer (which must be free()'ed) of ciphersuites for a given TLS version, and sets the 'ciphersuite_list_len' arg to the number of bytes in 'ciphersuite_list'. */ +void makeMissingCiphersuiteList(unsigned char **ciphersuite_list, size_t *ciphersuite_list_len, unsigned int tls_version) { + size_t ciphersuite_list_size = 1024; + + if (tls_version == 0) + tls_version = V1_0; + else if (tls_version == 1) + tls_version = V1_1; + else if (tls_version == 2) + tls_version = V1_2; + + *ciphersuite_list_len = 0; + *ciphersuite_list = calloc(ciphersuite_list_size, sizeof(unsigned char)); + if (*ciphersuite_list == NULL) { + fprintf(stderr, "Failed to create buffer for ciphersuite list.\n"); + exit(-1); + } + + for (int i = 0; i < (sizeof(missing_ciphersuites) / sizeof(struct missing_ciphersuite)); i++) { + /* Append only those that OpenSSL does not cover, and those that were not already accepted through a previous run. */ + if ((missing_ciphersuites[i].check_tls_versions & tls_version) && ((missing_ciphersuites[i].accepted_tls_versions & tls_version) == 0)) { + buffer_append_ushort(ciphersuite_list, &ciphersuite_list_size, ciphersuite_list_len, missing_ciphersuites[i].id); + } + } +} + +/* Marks a ciphersuite as found so that it is not re-tested again. */ +void markFoundCiphersuite(unsigned short server_cipher_id, unsigned int tls_version) { + if (tls_version == 0) + tls_version = V1_0; + else if (tls_version == 1) + tls_version = V1_1; + else if (tls_version == 2) + tls_version = V1_2; + + for (int i = 0; i < (sizeof(missing_ciphersuites) / sizeof(struct missing_ciphersuite)); i++) { + if (missing_ciphersuites[i].id == server_cipher_id) { + missing_ciphersuites[i].accepted_tls_versions |= tls_version; + break; + } + } +} + +/* Resolves an IANA cipher ID to its IANA name. Sets the cipher_bits argument to the cipher strength (or to -1 if unknown). Returns NULL if cipher ID is not found. */ +char *resolveCipherID(ushort cipher_id, int *cipher_bits) { + for (int i = 0; i < (sizeof(missing_ciphersuites) / sizeof(struct missing_ciphersuite)); i++) { + if (missing_ciphersuites[i].id == cipher_id) { + *cipher_bits = missing_ciphersuites[i].bits; + return missing_ciphersuites[i].protocol_name; + } + } + *cipher_bits = -1; + return NULL; +} + +/* Checks all ciphersuites that OpenSSL does not support. When version is 0, TLSv1.0 is tested. When set to 1, TLSv1.1 is tested. When set to 2, TLSv1.2 is tested. */ +int testMissingCiphers(struct sslCheckOptions *options, unsigned int version) { + int ret = false, s = 0; + unsigned char *ciphersuite_list = NULL, *client_hello = NULL, *tls_extensions = NULL; + unsigned int tls_version_low_byte = 1; + char *tls_printable_name = "TLSv1.0"; + + + tls_version_low_byte += version; + + if (version == 1) + tls_printable_name = "TLSv1.1"; + else if (version == 2) + tls_printable_name = "TLSv1.2"; + + while (1) { + unsigned short extension_length = 0, sni_list_length = 0, sni_length = 0; + unsigned long time_now = time(NULL); + unsigned char server_hello[128] = {0}; + size_t client_hello_size = 1024, client_hello_len = 0, ciphersuite_list_len = 0; + size_t tls_extensions_size = 256, tls_extensions_len = 0; + struct timeval tval_start = {0}, tval_end = {0}, tval_elapsed = {0}; + int cipher_bits = -1; + char *cipher_name = NULL; + + + gettimeofday(&tval_start, NULL); + + /* Allocate buffers for the Client Hello and TLS extensions. */ + client_hello = calloc(client_hello_size, sizeof(unsigned char)); + tls_extensions = calloc(tls_extensions_size, sizeof(unsigned char)); + if ((client_hello == NULL) || (tls_extensions == NULL)) { + fprintf(stderr, "Failed to allocate buffers for ClientHello.\n"); + exit(-1); + } + + /* Build the TLSv1 Record with the ClientHello message. */ + buffer_append_bytes(&client_hello, &client_hello_size, &client_hello_len, (unsigned char []) { + 0x16, // Content Type: Handshake (22) + 0x03, (unsigned char)tls_version_low_byte, // Version: TLS 1.x + 0x00, 0x00, // Length (to be filled in later) + 0x01, // Handshake Type: Client Hello + 0x00, 0x00, 0x00, // Length (to be filled in later) + 0x03, (unsigned char)tls_version_low_byte, // Version: TLS 1.x + }, 11); + + /* "Random" 32 bytes. */ + uint32_t rand = htonl(time_now); + buffer_append_uint32_t(&client_hello, &client_hello_size, &client_hello_len, rand); /* The first 4 bytes is the timestamp. */ + + for (int i = 1; i < 8; i++) { + rand = rand + (time_now ^ (uint32_t)((~(i + 0) << 24) | (~(i + 1) << 16) | (~(i + 2) << 8) | (~(i + 3) << 0))); + buffer_append_uint32_t(&client_hello, &client_hello_size, &client_hello_len, rand); + } + + /* Session ID Length: 0 */ + buffer_append_bytes(&client_hello, &client_hello_size, &client_hello_len, + (unsigned char []) { 0x00 }, 1); + + /* Construct the list of ciphersuites. */ + makeMissingCiphersuiteList(&ciphersuite_list, &ciphersuite_list_len, version); + + /* Add the length (in bytes) of the ciphersuites list to the Client Hello. */ + buffer_append_ushort(&client_hello, &client_hello_size, &client_hello_len, ciphersuite_list_len); + + /* Append the list of ciphersuites to the Client Hello. */ + buffer_append_bytes(&client_hello, &client_hello_size, &client_hello_len, ciphersuite_list, ciphersuite_list_len); + + /* Free the ciphersuite list since we are done with it. */ + FREE(ciphersuite_list); + ciphersuite_list_len = 0; + + /* Add the compression options. */ + buffer_append_bytes(&client_hello, &client_hello_size, &client_hello_len, (unsigned char []) { + 0x01, // Compression Methods Length (1) + 0x00 // Compression Method: null (0) + }, 2); + + /* Add the length of the extensions (to be filled in later). */ + buffer_append_ushort(&tls_extensions, &tls_extensions_size, &tls_extensions_len, 0); + + /* Extension: server name */ + sni_length = strlen(options->sniname); + sni_list_length = sni_length + 3; + extension_length = sni_list_length + 2; + + buffer_append_ushort(&tls_extensions, &tls_extensions_size, &tls_extensions_len, 0x0000); /* Extension: server_name */ + buffer_append_ushort(&tls_extensions, &tls_extensions_size, &tls_extensions_len, extension_length); + buffer_append_ushort(&tls_extensions, &tls_extensions_size, &tls_extensions_len, sni_list_length); + buffer_append_bytes(&tls_extensions, &tls_extensions_size, &tls_extensions_len, (unsigned char []) { 0x00 /* Server Name Type: host_name */ }, 1); + buffer_append_ushort(&tls_extensions, &tls_extensions_size, &tls_extensions_len, sni_length); /* The length of the hostname. */ + buffer_append_bytes(&tls_extensions, &tls_extensions_size, &tls_extensions_len, (unsigned char *)options->sniname, sni_length); /* The hostname itself. */ + + /* Extension: ec_point_formats */ + buffer_append_bytes(&tls_extensions, &tls_extensions_size, &tls_extensions_len, (unsigned char []) { + 0x00, 0x0b, // Extension: ec_point_formats (11) + 0x00, 0x04, // Extension Length (4) + 0x03, // EC Point Formats Length (3) + 0x00, // Uncompressed + 0x01, // ansiX962_compressed_prime + 0x02, // ansiX962_compressed_char2 + }, 8); + + /* Extension: supported_groups */ + buffer_append_bytes(&tls_extensions, &tls_extensions_size, &tls_extensions_len, (unsigned char []) { + 0x00, 0x0a, // Extension: supported_groups (10) + 0x00, 0x1c, // Extension Length (28) + 0x00, 0x1a, // Supported Groups List Length (26) + 0x00, 0x17, // secp256r1 + 0x00, 0x19, // secp521r1 + 0x00, 0x1c, // brainpoolP512r1 + 0x00, 0x1b, // brainpoolP384r1 + 0x00, 0x18, // secp384r1 + 0x00, 0x1a, // brainpoolP256r1 + 0x00, 0x16, // secp256k1 + 0x00, 0x0e, // sect571r1 + 0x00, 0x0d, // sect571k1 + 0x00, 0x0b, // sect409k1 + 0x00, 0x0c, // sect409r1 + 0x00, 0x09, // sect283k1 + 0x00, 0x0a, // sect283r1 + }, 32); + + /* Extension: SessionTicket TLS */ + buffer_append_bytes(&tls_extensions, &tls_extensions_size, &tls_extensions_len, (unsigned char []) { + 0x00, 0x23, // Extension: SessionTicket TLS (35) + 0x00, 0x00, // Extension Length (0) + }, 4); + + /* Set the extension length. */ + unsigned short us = htons(tls_extensions_len - 2); + memcpy(tls_extensions, &us, sizeof(us)); + + /* Add the extensions to the Client Hello. */ + buffer_append_bytes(&client_hello, &client_hello_size, &client_hello_len, tls_extensions, tls_extensions_len); + + /* Free the extensions since we are done with them. */ + FREE(tls_extensions); + tls_extensions_len = 0; + tls_extensions_size = 0; + + /* Set the length of the Client Hello. */ + client_hello[6] = 0; + us = htons(client_hello_len - 9); + memcpy(client_hello + 7, &us, sizeof(us)); + + /* Set the length of the Record Layer. */ + us = htons(client_hello_len - 5); + memcpy(client_hello + 3, &us, sizeof(us)); + + /* Now connect to the target server. */ + s = tcpConnect(options); + if (s == 0) + goto done; + + /* Send the Client Hello message. */ + if (send(s, client_hello, client_hello_len, 0) <= 0) { + printf_error("send() failed while sending Client Hello: %d (%s)\n", errno, strerror(errno)); + goto done; /* Returns false. */ + } + FREE(client_hello); + client_hello_size = 0; + client_hello_len = 0; + + /* Read the first 5 bytes to get the Content Type, Version, and Length fields. */ + int bytes_read = 0, n = 0; + while (bytes_read < 5) { + n = recv(s, server_hello + bytes_read, 5 - bytes_read, 0); + if (n <= 0) { + if ((errno != 0) && (errno != ECONNRESET)) + printf_error("recv() failed while reading Server Hello: %d (%s)\n", errno, strerror(errno)); + goto done; /* Returns false. */ + } + bytes_read += n; + } + size_t server_hello_len = bytes_read; + + /* Check that the TLS version returned is what we sent earlier. */ + if ((server_hello[1] != 0x03) || (server_hello[2] != (unsigned char)tls_version_low_byte)) + goto done; + + /* At this point, the test is considered a success, even if the server rejects our Client Hello. */ + ret = true; + + /* Ensure that the Content Type is Handshake (22). */ + if (server_hello[0] != 0x16) + goto done; + + /* Get the length of the Server Hello record. */ + unsigned short packet_len = (server_hello[3] << 8) | server_hello[4]; + + /* Ensure that our buffer can hold the entire record. */ + if (packet_len > sizeof(server_hello)) { + fprintf(stderr, "Error: size of server_hello (%zu) is not large enough for Server Hello (%u).\n", sizeof(server_hello), packet_len); + exit(-1); + } + + /* Read in the Server Hello record. */ + bytes_read = 0; + while (bytes_read < packet_len) { + n = recv(s, server_hello + server_hello_len + bytes_read, packet_len - bytes_read, 0); + if (n <= 0) { + if ((errno != 0) && (errno != ECONNRESET)) + printf_error("recv() failed while reading Server Hello: %d (%s)\n", errno, strerror(errno)); + goto done; + } + bytes_read += n; + } + server_hello_len += bytes_read; + + /* Close the socket, since we're done reading. */ + CLOSE(s); + + /* Ensure that the Handshake Type is Server Hello (2). */ + if (server_hello[5] != 0x02) + goto done; + + /* Get the length of the session ID. We must jump over this to reach the ciphersuite selected by the server. */ + unsigned int session_id_len = server_hello[43]; + + /* Its impossible for one byte to overflow an unsigned int (on any modern hardware), but still... */ + if ((session_id_len + 43 + 2 + 1) < session_id_len) { + fprintf(stderr, "Error: potential integer overflow averted (%d).\n", session_id_len); + exit(-1); + } + + /* Check that the session ID length wouldn't put us past our buffer boundary. */ + if ((session_id_len + 43 + 2 + 1) > sizeof(server_hello)) { + fprintf(stderr, "Error: size of server_hello (%zu) is not large enough to reach cipher suite (%u).\n", sizeof(server_hello), session_id_len + 43 + 2); + exit(-1); + } + + /* Extract the cipher ID. */ + unsigned short cipher_id = (server_hello[session_id_len + 43 + 1] << 8) | server_hello[session_id_len + 43 + 2]; + + /* Mark this cipher ID as supported by the server, so when we loop again, the next ciphersuite list doesn't include it. */ + markFoundCiphersuite(cipher_id, version); + + /* Get the IANA name and cipher bit strength (maybe -1 when unknown). */ + cipher_name = resolveCipherID(cipher_id, &cipher_bits); + + /* Get the number of milliseconds that have elapsed. */ + gettimeofday(&tval_end, NULL); + timersub(&tval_end, &tval_start, &tval_elapsed); + unsigned int milliseconds_elapsed = tval_elapsed.tv_sec * 1000 + (int)tval_elapsed.tv_usec / 1000; + + /* Output the cipher information. */ + outputCipher(options, NULL, tls_printable_name, cipher_id, cipher_name, cipher_bits, 1, milliseconds_elapsed, ""); + } + + done: + CLOSE(s); + FREE(ciphersuite_list); + FREE(tls_extensions); + FREE(client_hello); + return ret; +} + /* MinGW doesn't have a memmem() implementation. */ #ifdef _WIN32 diff --git a/sslscan.h b/sslscan.h index 1aad0f2..ee3a216 100644 --- a/sslscan.h +++ b/sslscan.h @@ -37,6 +37,8 @@ #ifndef HAVE_SSLSCAN_H_ #define HAVE_SSLSCAN_H_ +#include "missing_ciphersuites.h" + // Defines... #define false 0 #define true 1 @@ -69,6 +71,12 @@ #define printf_xml(format, ...) if (options->xmlOutput) fprintf(options->xmlOutput, format, ##__VA_ARGS__) #define printf_verbose(format, ...) if (options->verbose) printf(format, ##__VA_ARGS__) +/* Calls close() on a file descriptor, then sets it to zero to prevent accidental re-use. */ +#define CLOSE(fd) { if ((fd) != 0) { close((fd)); (fd) = 0; } } + +/* Calls free() on a pointer, then explicitly sets it to NULL to avoid use-after-free. */ +#define FREE(ptr) { free((ptr)); (ptr) = NULL; } + /* Frees an SSL pointer, and explicitly sets it to NULL to avoid use-after-free. */ #define FREE_SSL(ssl) { if ((ssl) != NULL) { SSL_free((ssl)); (ssl) = NULL; } } @@ -266,17 +274,23 @@ struct ocsp_cert_id_st { #endif // Utilities +void buffer_append_bytes(unsigned char **buffer, size_t *buf_size, size_t *buf_len, unsigned char *bytes, size_t bytes_len); +void buffer_append_ushort(unsigned char **buffer, size_t *buf_size, size_t *buf_len, unsigned short s); +void buffer_append_uint32_t(unsigned char **buffer, size_t *buf_size, size_t *buf_len, uint32_t i); SSL_CTX *CTX_new(const SSL_METHOD *method); int fileExists(char *); +void findMissingCiphers(); +void makeMissingCiphersuiteList(unsigned char **ciphersuite_list, size_t *ciphersuite_list_len, unsigned int tls_version); +void markFoundCiphersuite(unsigned short server_cipher_id, unsigned int tls_version); +int ocsp_certid_print(BIO *bp, OCSP_CERTID *a, int indent); +static int ocsp_resp_cb(SSL *s, void *arg); void readLine(FILE *, char *, int); -ssize_t sendString(int, const char[]); int readOrLogAndClose(int, void *, size_t, const struct sslCheckOptions *); -const char *printableSslMethod(const SSL_METHOD *); +char *resolveCipherID(ushort cipher_id, int *cipher_bits); static int password_callback(char *, int, int, void *); +const char *printableSslMethod(const SSL_METHOD *); +ssize_t sendString(int, const char[]); int ssl_print_tmp_key(struct sslCheckOptions *, SSL *s); -static int ocsp_resp_cb(SSL *s, void *arg); -int ocsp_certid_print(BIO *bp, OCSP_CERTID *a, int indent); - int tcpConnect(struct sslCheckOptions *); // Tests @@ -292,10 +306,10 @@ int testfallback(struct sslCheckOptions *, const SSL_METHOD *); #endif int testHeartbleed(struct sslCheckOptions *, const SSL_METHOD *); int testCipher(struct sslCheckOptions *, const SSL_METHOD *); +int testMissingCiphers(struct sslCheckOptions *options, unsigned int version); int testProtocolCiphers(struct sslCheckOptions *, const SSL_METHOD *); int testConnection(struct sslCheckOptions *); int testHost(struct sslCheckOptions *); - int loadCerts(struct sslCheckOptions *); int checkCertificateProtocols(struct sslCheckOptions *, const SSL_METHOD *); int checkCertificate(struct sslCheckOptions *, const SSL_METHOD *); diff --git a/tools/iana_tls_ciphersuite_parser.py b/tools/iana_tls_ciphersuite_parser.py new file mode 100755 index 0000000..be06258 --- /dev/null +++ b/tools/iana_tls_ciphersuite_parser.py @@ -0,0 +1,96 @@ +#!/usr/bin/python3 + +# +# Copyright (C) 2019 Joe Testa +# +# This tool will parse the list of TLS ciphersuites from IANA +# (https://www.iana.org/assignments/tls-parameters/tls-parameters.xml) into a C-struct +# for use in missing_ciphersuites.h. +# + +import csv, sys +from datetime import date + + +# We must be given a path to a CSV file with the ciphersuites. It can be obtained from +# . +if len(sys.argv) != 2: + print("\nUsage: %s tls_ciphers.csv\n\nHint: copy the TLS table in CSV format from .\n" % sys.argv[0]) + exit(0) + +csv_file = sys.argv[1] + +print("/* Auto-generated by %s on %s. */" % (sys.argv[0], date.today().strftime("%B %d, %Y"))) +print("struct missing_ciphersuite missing_ciphersuites[] = {") +with open(csv_file, 'r') as f: + reader = csv.reader(f) + for row in reader: + id = row[0] + cipher_name = row[1] + + # Skip the header. + if '0x' not in id: + continue + + # Skip reserved or unassigned ranges. Also skip SCSV ciphers. + if ('Reserved' in cipher_name) or ('Unassigned' in cipher_name) or ('TLS_FALLBACK_SCSV' in cipher_name) or ('TLS_EMPTY_RENEGOTIATION_INFO_SCSV' in cipher_name): + continue + + # Convert '0xC0,0x87' to '0xC087' + parsed_id = id[0:4] + id[7:9] + if len(parsed_id) != 6: + print("Error: parsed ID is not length 6: %s" % parsed_id) + exit -1 + + # Make an educated guess of the cipher's bit strength based on its name. + bits = -1 + if 'AES_128' in cipher_name: + bits = 128 + elif 'AES_256' in cipher_name: + bits = 256 + elif 'CHACHA20' in cipher_name: + bits = 256 + elif 'CAMELLIA_128' in cipher_name: + bits = 128 + elif 'CAMELLIA_256' in cipher_name: + bits = 256 + elif 'ARIA_128' in cipher_name: + bits = 128 + elif 'ARIA_256' in cipher_name: + bits = 256 + elif '3DES' in cipher_name: + bits = 112 + elif 'DES40' in cipher_name: + bits = 40 + elif '_DES_' in cipher_name: + bits = 56 + elif 'RC4_128' in cipher_name: + bits = 128 + elif 'RC4_40' in cipher_name: + bits = 40 + elif 'IDEA' in cipher_name: + bits = 128 + elif '_RC2_' in cipher_name: + bits = 40 + elif 'GOSTR341112_256' in cipher_name: + bits = 256 + elif '_SM4_' in cipher_name: # See http://www.gmbz.org.cn/upload/2018-04-04/1522788048733065051.pdf + bits = 128 + + print(' {%s, "%s", %d, VALL, 0},' % (parsed_id, cipher_name, bits)) + + # These ciphers are reserved for private use. Kind of like the 10.0.0.0/8 IPv4 + # addresses. + print("\n /* The ciphers below are reserved for private use (see RFC8446). */") + for i in range(0, 256): + low_byte = hex(i)[2:].upper() + if len(low_byte) == 1: + low_byte = '0' + low_byte + + parsed_id = '0xFF' + low_byte + cipher_name = 'PRIVATE_CIPHER_%d' % i + bits = -1 + print(' {%s, "%s", %d, VALL, 0},' % (parsed_id, cipher_name, bits)) + +print("};") +exit 0 From 3f4dbc913fdb4ebb3a6822afd63828f6b8cfc9b5 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Tue, 10 Dec 2019 23:28:38 -0500 Subject: [PATCH 31/52] Windows build fixes. --- sslscan.c | 13 ++++++++++--- sslscan.h | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/sslscan.c b/sslscan.c index 36aae48..5abeb32 100644 --- a/sslscan.c +++ b/sslscan.c @@ -118,6 +118,13 @@ #include #endif +/* Format specifier for printing a size_t. */ +#ifdef _WIN32 + #define SIZE_T_FMT PRIu64 +#else + #define SIZE_T_FMT "zu" +#endif + #include "sslscan.h" #if OPENSSL_VERSION_NUMBER < 0x1010100fL @@ -4498,7 +4505,7 @@ void markFoundCiphersuite(unsigned short server_cipher_id, unsigned int tls_vers } /* Resolves an IANA cipher ID to its IANA name. Sets the cipher_bits argument to the cipher strength (or to -1 if unknown). Returns NULL if cipher ID is not found. */ -char *resolveCipherID(ushort cipher_id, int *cipher_bits) { +char *resolveCipherID(unsigned short cipher_id, int *cipher_bits) { for (int i = 0; i < (sizeof(missing_ciphersuites) / sizeof(struct missing_ciphersuite)); i++) { if (missing_ciphersuites[i].id == cipher_id) { *cipher_bits = missing_ciphersuites[i].bits; @@ -4702,7 +4709,7 @@ int testMissingCiphers(struct sslCheckOptions *options, unsigned int version) { /* Ensure that our buffer can hold the entire record. */ if (packet_len > sizeof(server_hello)) { - fprintf(stderr, "Error: size of server_hello (%zu) is not large enough for Server Hello (%u).\n", sizeof(server_hello), packet_len); + fprintf(stderr, "Error: size of server_hello (%"SIZE_T_FMT") is not large enough for Server Hello (%u).\n", sizeof(server_hello), packet_len); exit(-1); } @@ -4737,7 +4744,7 @@ int testMissingCiphers(struct sslCheckOptions *options, unsigned int version) { /* Check that the session ID length wouldn't put us past our buffer boundary. */ if ((session_id_len + 43 + 2 + 1) > sizeof(server_hello)) { - fprintf(stderr, "Error: size of server_hello (%zu) is not large enough to reach cipher suite (%u).\n", sizeof(server_hello), session_id_len + 43 + 2); + fprintf(stderr, "Error: size of server_hello (%"SIZE_T_FMT") is not large enough to reach cipher suite (%u).\n", sizeof(server_hello), session_id_len + 43 + 2); exit(-1); } diff --git a/sslscan.h b/sslscan.h index ee3a216..640f9fd 100644 --- a/sslscan.h +++ b/sslscan.h @@ -286,7 +286,7 @@ int ocsp_certid_print(BIO *bp, OCSP_CERTID *a, int indent); static int ocsp_resp_cb(SSL *s, void *arg); void readLine(FILE *, char *, int); int readOrLogAndClose(int, void *, size_t, const struct sslCheckOptions *); -char *resolveCipherID(ushort cipher_id, int *cipher_bits); +char *resolveCipherID(unsigned short cipher_id, int *cipher_bits); static int password_callback(char *, int, int, void *); const char *printableSslMethod(const SSL_METHOD *); ssize_t sendString(int, const char[]); From cbbf36c5e57c8d0d912f22718ff3eb601f42b074 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Tue, 10 Dec 2019 23:38:36 -0500 Subject: [PATCH 32/52] Now marking SM4 and GOST-based ciphersuites as yellow (they are developed by the Chinese and Russian governments, respectively). --- sslscan.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sslscan.c b/sslscan.c index 5abeb32..4397e00 100644 --- a/sslscan.c +++ b/sslscan.c @@ -1640,6 +1640,10 @@ void outputCipher(struct sslCheckOptions *options, SSL *ssl, const char *cleanSs printf("%s%-29s%s", COL_RED, ciphername, RESET); } else if (strstr(ciphername, "RC4") || strstr(ciphername, "DES")) { printf("%s%-29s%s", COL_YELLOW, ciphername, RESET); + } else if (strstr(ciphername, "_SM4_")) { /* Developed by Chinese government */ + printf("%s%-29s%s", COL_YELLOW, ciphername, RESET); + } else if (strstr(ciphername, "_GOSTR341112_")) { /* Developed by Russian government */ + printf("%s%-29s%s", COL_YELLOW, ciphername, RESET); } else if ((strstr(ciphername, "CHACHA20") || (strstr(ciphername, "GCM"))) && strstr(ciphername, "DHE")) { printf("%s%-29s%s", COL_GREEN, ciphername, RESET); } else { From f87b58c1aefb368b0b27b1f2e0348a69f7a61421 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Wed, 11 Dec 2019 09:33:38 -0500 Subject: [PATCH 33/52] resolveCipherID() now returns 'UNKNOWN_CIPHER' instead of NULL when an ID cannot be resolved. --- sslscan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sslscan.c b/sslscan.c index 4397e00..32b2076 100644 --- a/sslscan.c +++ b/sslscan.c @@ -4508,7 +4508,7 @@ void markFoundCiphersuite(unsigned short server_cipher_id, unsigned int tls_vers } } -/* Resolves an IANA cipher ID to its IANA name. Sets the cipher_bits argument to the cipher strength (or to -1 if unknown). Returns NULL if cipher ID is not found. */ +/* Resolves an IANA cipher ID to its IANA name. Sets the cipher_bits argument to the cipher strength (or to -1 if unknown). Returns "UNKNOWN_CIPHER if cipher ID is not found. */ char *resolveCipherID(unsigned short cipher_id, int *cipher_bits) { for (int i = 0; i < (sizeof(missing_ciphersuites) / sizeof(struct missing_ciphersuite)); i++) { if (missing_ciphersuites[i].id == cipher_id) { @@ -4517,7 +4517,7 @@ char *resolveCipherID(unsigned short cipher_id, int *cipher_bits) { } } *cipher_bits = -1; - return NULL; + return "UNKNOWN_CIPHER"; } /* Checks all ciphersuites that OpenSSL does not support. When version is 0, TLSv1.0 is tested. When set to 1, TLSv1.1 is tested. When set to 2, TLSv1.2 is tested. */ From b930d9ce2856daffd770ae4c9245dda1e4c0dcee Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Wed, 11 Dec 2019 21:33:12 -0500 Subject: [PATCH 34/52] Merged Docker testing framework. --- Makefile | 3 + docker_test.sh | 370 ++++++++++++++++++++ docker_test/Dockerfile | 21 ++ docker_test/ca_cert.pem | 31 ++ docker_test/ca_key.pem | 52 +++ docker_test/cert_1024.crt | 22 ++ docker_test/cert_2048.crt | 25 ++ docker_test/cert_3072.crt | 27 ++ docker_test/dhparams_1024.pem | 5 + docker_test/dhparams_2048.pem | 8 + docker_test/dhparams_3072.pem | 11 + docker_test/expected_output/test_1.txt | 102 ++++++ docker_test/expected_output/test_10.txt | 20 ++ docker_test/expected_output/test_11.txt | 21 ++ docker_test/expected_output/test_2.txt | 27 ++ docker_test/expected_output/test_3.txt | 27 ++ docker_test/expected_output/test_4.txt | 69 ++++ docker_test/expected_output/test_5.txt | 157 +++++++++ docker_test/expected_output/test_6.txt | 39 +++ docker_test/expected_output/test_7.txt | 55 +++ docker_test/expected_output/test_8.txt | 77 ++++ docker_test/expected_output/test_9.txt | 20 ++ docker_test/key_1024.pem | 15 + docker_test/key_2048.pem | 27 ++ docker_test/key_3072.pem | 39 +++ docker_test/key_notes.txt | 8 + docker_test/nginx_site_client_cert_required | 21 ++ docker_test/nginx_test9.conf | 21 ++ 28 files changed, 1320 insertions(+) create mode 100755 docker_test.sh create mode 100644 docker_test/Dockerfile create mode 100644 docker_test/ca_cert.pem create mode 100644 docker_test/ca_key.pem create mode 100644 docker_test/cert_1024.crt create mode 100644 docker_test/cert_2048.crt create mode 100644 docker_test/cert_3072.crt create mode 100644 docker_test/dhparams_1024.pem create mode 100644 docker_test/dhparams_2048.pem create mode 100644 docker_test/dhparams_3072.pem create mode 100644 docker_test/expected_output/test_1.txt create mode 100644 docker_test/expected_output/test_10.txt create mode 100644 docker_test/expected_output/test_11.txt create mode 100644 docker_test/expected_output/test_2.txt create mode 100644 docker_test/expected_output/test_3.txt create mode 100644 docker_test/expected_output/test_4.txt create mode 100644 docker_test/expected_output/test_5.txt create mode 100644 docker_test/expected_output/test_6.txt create mode 100644 docker_test/expected_output/test_7.txt create mode 100644 docker_test/expected_output/test_8.txt create mode 100644 docker_test/expected_output/test_9.txt create mode 100644 docker_test/key_1024.pem create mode 100644 docker_test/key_2048.pem create mode 100644 docker_test/key_3072.pem create mode 100644 docker_test/key_notes.txt create mode 100644 docker_test/nginx_site_client_cert_required create mode 100644 docker_test/nginx_test9.conf diff --git a/Makefile b/Makefile index a3880e1..d3e6462 100644 --- a/Makefile +++ b/Makefile @@ -142,6 +142,9 @@ openssl/libcrypto.a: openssl/Makefile static: openssl/libcrypto.a $(MAKE) -j $(NUM_PROCS) sslscan STATIC_BUILD=TRUE +test: static + ./docker_test.sh + clean: if [ -d openssl ]; then ( rm -rf openssl ); fi; rm -f sslscan diff --git a/docker_test.sh b/docker_test.sh new file mode 100755 index 0000000..4513c3b --- /dev/null +++ b/docker_test.sh @@ -0,0 +1,370 @@ +#!/bin/bash + +# +# Copyright (C) 2019 Joe Testa +# +# This script (adapted from the ssh-audit project) will set up a docker image with +# multiple SSL/TLS servers. They are each executed one at a time, and sslscan is run +# against them. The output of sslscan is compared against the expected output. If +# they match, the test passes; otherwise the test fails. +# +# +# For debugging purposes, here is a cheat sheet for manually running the docker image: +# +# docker run -p 4443:443 --security-opt seccomp:unconfined -it sslscan-test:1 /bin/bash +# + +# +# Running this script with no arguments causes it to build the docker image (if it +# doesn't yet exist), then run all tests. +# +# Running the script with a test number argument (i.e.: './docker_test.sh 2') will +# run the docker image for test #2 only (in the background) and do nothing else. This +# allows the test itself to be debugged. +# + + +# This is the docker tag for the image. If this tag doesn't exist, then we assume the +# image is out of date, and generate a new one with this tag. +IMAGE_VERSION=1 + +# This is the name of our docker image. +IMAGE_NAME=sslscan-test + + +# Terminal colors. +CLR="\033[0m" +RED="\033[0;31m" +GREEN="\033[0;32m" +REDB="\033[1;31m" # Red + bold +YELLOWB="\033[1;33m" # Yellow + bold +GREENB="\033[1;32m" # Green + bold + + +# Number of processors on this system (used to compile parallel builds). +NUM_PROCS=`/usr/bin/nproc --all 2> /dev/null` +if [[ $NUM_PROCS == '' ]]; then + NUM_PROCS=4 +fi + + +# Returns 0 if current docker image exists. +function check_if_docker_image_exists { + images=`docker image ls | egrep "$IMAGE_NAME[[:space:]]+$IMAGE_VERSION"` +} + + +# Compile all versions of OpenSSL. +function compile_openssl_all { + compile_openssl '1.0.0' + compile_openssl '1.0.2' + compile_openssl '1.1.1' +} + + +# Compile a specific version of OpenSSL. +function compile_openssl { + version=$1 + + git_tag= + compile_args= + precompile_command= + output_dir= + compile_num_procs=$NUM_PROCS + if [[ $version == '1.0.0' ]]; then + git_tag="OpenSSL_1_0_0-stable" + compile_args="enable-weak-ssl-ciphers enable-ssl2 zlib no-shared" + precompile_command="make depend" + output_dir="openssl_v1.0.0_dir" + compile_num_procs=1 # Compilation randomly fails when done in parallel. + elif [[ $version == '1.0.2' ]]; then + git_tag="OpenSSL_1_0_2-stable" + compile_args="enable-weak-ssl-ciphers enable-ssl2 zlib" + precompile_command="make depend" + output_dir="openssl_v1.0.2_dir" + elif [[ $version == '1.1.1' ]]; then + git_tag="OpenSSL_1_1_1-stable" + compile_args="enable-weak-ssl-ciphers no-shared zlib" + output_dir="openssl_v1.1.1_dir" + else + echo -e "${REDB}Error: OpenSSL v${version} is unknown!${CLR}" + exit 1 + fi + + # Download OpenSSL from github. + echo -e "\n${YELLOWB}Downloading OpenSSL v${version}...${CLR}\n" + git clone -b $git_tag https://github.com/openssl/openssl/ $output_dir + + # Configure and compile it. + echo -e "\n\n${YELLOWB}Compiling OpenSSL v${version} with \"-j ${compile_num_procs}\"...${CLR}" + pushd $output_dir + ./config $compile_args + if [[ $precompile_command != '' ]]; then $precompile_command; fi + make -j $compile_num_procs + + # Ensure that the 'openssl' command-line tool was built. + if [[ ! -f "apps/openssl" ]]; then + echo -e "${REDB}Error: compilation failed! apps/openssl not found.${CLR}\n\nStrangely, sometimes OpenSSL v1.0.0 fails for no reason; simply running this script again and changing nothing fixes the problem.\n\n" + exit 1 + fi + + # Copy the 'openssl' app to the top-level docker building dir as, e.g. 'openssl_prog_v1.0.0'. Then we can delete the source code directory and move on. + cp "apps/openssl" "../openssl_prog_v${version}" + popd + + # Delete the source code directory now that we built the 'openssl' tool and moved it out. + rm -rf $output_dir + echo -e "\n\n${YELLOWB}Compilation of v${version} finished.${CLR}\n\n" +} + + +# Creates a new docker image. +function create_docker_image { + # Create a new temporary directory. + TMP_DIR=`mktemp -d /tmp/sslscan-docker-XXXXXXXXXX` + + # Copy the Dockerfile and all files in the test/docker/ dir to our new temp directory. + find docker_test -maxdepth 1 -type f | xargs cp -t $TMP_DIR + + # Make the temp directory our working directory for the duration of the build + # process. + pushd $TMP_DIR > /dev/null + + # Compile the versions of OpenSSL. + compile_openssl_all + + # Now build the docker image! + echo -e "${YELLOWB}Creating docker image...${CLR}" + docker build --tag $IMAGE_NAME:$IMAGE_VERSION . + echo -e "${YELLOWB}Docker image creation complete.${CLR}" + + popd > /dev/null + rm -rf $TMP_DIR +} + + +# Runs all tests with the debug flag disabled. +function run_tests { + run_test_1 "0" + run_test_2 "0" + run_test_3 "0" + run_test_4 "0" + run_test_5 "0" + run_test_6 "0" + run_test_7 "0" + run_test_8 "0" + run_test_9 "0" + run_test_10 "0" + run_test_11 "0" +} + + +# Mostly default v1.0.2 (SSLv3, TLSv1.0, TLSv1.1, TLSv1.2) +function run_test_1 { + run_test $1 '1' "/openssl_v1.0.2/openssl s_server -accept 443 -dhparam /etc/ssl/dhparams_2048.pem -key /etc/ssl/key_2048.pem -cert /etc/ssl/cert_2048.crt" "" +} + + +# SSLv2 with 1024-bit certificate & DH parameters. +function run_test_2 { + run_test $1 '2' "/openssl_v1.0.2/openssl s_server -ssl2 -accept 443 -dhparam /etc/ssl/dhparams_1024.pem -key /etc/ssl/key_1024.pem -cert /etc/ssl/cert_1024.crt" "" +} + + +# SSLv3 with 1024-bit certificate & DH parameters. +function run_test_3 { + run_test $1 '3' "/openssl_v1.0.2/openssl s_server -ssl3 -accept 443 -dhparam /etc/ssl/dhparams_1024.pem -key /etc/ssl/key_1024.pem -cert /etc/ssl/cert_1024.crt" "" +} + + +# Mostly default v1.1.1. +function run_test_4 { + run_test $1 '4' "/openssl_v1.1.1/openssl s_server -accept 443 -dhparam /etc/ssl/dhparams_3072.pem -key /etc/ssl/key_3072.pem -cert /etc/ssl/cert_3072.crt" "" +} + + +# All ciphers with SSLv2 through TLSv1.2 with 1024-bit certificate & DH parameters. +function run_test_5 { + run_test $1 '5' "/openssl_v1.0.2/openssl s_server -cipher ALL -accept 443 -dhparam /etc/ssl/dhparams_1024.pem -key /etc/ssl/key_1024.pem -cert /etc/ssl/cert_1024.crt" "" +} + + +# TLSv1.3 with all ciphers. +function run_test_6 { + run_test $1 '6' "/openssl_v1.1.1/openssl s_server -tls1_3 -ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256 -accept 443 -dhparam /etc/ssl/dhparams_3072.pem -key /etc/ssl/key_3072.pem -cert /etc/ssl/cert_3072.crt" "" +} + + +# Default v1.0.0. +function run_test_7 { + run_test $1 '7' "/openssl_v1.0.0/openssl s_server -accept 443 -key /etc/ssl/key_3072.pem -cert /etc/ssl/cert_3072.crt" "" +} + + +# v1.0.0 with 'ALL:eNULL' ciphers. +function run_test_8 { + run_test $1 '8' "/openssl_v1.0.0/openssl s_server -accept 443 -cipher ALL:eNULL -key /etc/ssl/key_3072.pem -cert /etc/ssl/cert_3072.crt" "" +} + + +# Runs nginx with client certificate checking (signed by the CA in docker_test/ca_cert.pem). sslscan will connect and make an HTTP request (--http). The HTTP response code should be 200 to signify that the certificate was accepted. Otherwise, nginx returns HTTP code 400 if no client certificates were presented. +function run_test_9 { + run_test $1 '9' "/usr/sbin/nginx -c /etc/nginx/nginx_test9.conf" "--no-fallback --no-renegotiation --no-compression --no-heartbleed --certs=docker_test/cert_3072.crt --pk=docker_test/key_3072.pem --http" +} + + +# Runs nginx with client certificate checking, just as above. Except this time, we connect with no certificate. The HTTP response code should be "400 Bad Request". +function run_test_10 { + run_test $1 '10' "/usr/sbin/nginx -c /etc/nginx/nginx_test9.conf" "--no-fallback --no-renegotiation --no-compression --no-heartbleed --http" +} + + +# Makes an OCSP request to www.amazon.com. The horrible Perl command that comes after it will filter out the timestamps and other variable data from the response, otherwise the diff would fail. +function run_test_11 { + run_test_internet '11' "./sslscan --ocsp --no-ciphersuites --no-fallback --no-renegotiation --no-compression --no-heartbleed --no-check-certificate www.amazon.com | perl -pe 'BEGIN{undef $/;} s/Connected to .+?$/Connected to\033[0m/smg; s/Responder Id: .+?$/Responder Id:/smg; s/Produced At: .+?$/Produced At:/smg; s/Hash Algorithm: .+?$/Hash Algorithm:/smg; s/Issuer Name Hash: .+?$/Issuer Name Hash:/smg; s/Issuer Key Hash: .+?$/Issuer Key Hash:/smg; s/Serial Number: .+?$/Serial Number:/smg; s/This Update: .+?$/This Update:/smg; s/Next Update: .+?$/Next Update:/smg; s/Response Single Extensions:.+?\n\n/\n\n/smg;'" +} + + +# Run a test. Set the first argument to '1' to enable test debugging. +# Second argument is the test number to run. Third argument is the executable and +# its args to be run inside the container.. +function run_test { + debug=$1 + test_number=$2 + server_exec=$3 + sslscan_additional_args=$4 + + test_result_stdout="${TEST_RESULT_DIR}/test_${test_number}.txt" + expected_result_stdout="docker_test/expected_output/test_${test_number}.txt" + + # Run the container in the background. Route port 4443 on the outside to port 443 on the inside. + cid=`docker run -d -p 4443:443 -t ${IMAGE_NAME}:${IMAGE_VERSION} ${server_exec}` + if [[ $? != 0 ]]; then + echo -e "${REDB}Failed to run docker image! (exit code: $?)${CLR}" + exit 1 + fi + + # If debugging is enabled, just run the container. Don't do any output comparison. + if [[ $debug == 1 ]]; then + echo -e "\nExecuted in container: ${server_exec}\n\nTerminate container with: docker container stop -t 0 ${cid}\n\nHint: run sslscan against localhost on port 4443, not 443.\n" + return + fi + + # Run sslscan and cut out the first two lines. Those contain the version number + # and local version of OpenSSL, which can change over time (and when they do, this + # would break the test if they were left in). + ./sslscan $sslscan_additional_args localhost:4443 | tail -n +3 > $test_result_stdout + if [[ $? != 0 ]]; then + echo -e "${REDB}Failed to run sslscan! (exit code: $?)${CLR}" + docker container stop -t 0 $cid > /dev/null + exit 1 + fi + + # Stop the container now that we captured the sslscan output. + docker container stop -t 0 $cid > /dev/null + if [[ $? != 0 ]]; then + echo -e "${REDB}Failed to stop docker container ${cid}! (exit code: $?)${CLR}" + exit 1 + fi + + # If the expected output file doesn't exist, give the user all the info we have so they can fix this. + if [[ ! -f ${expected_result_stdout} ]]; then + test_result_stdout_actual=`cat ${test_result_stdout}` + echo -e "\n${REDB}Error:${CLR} expected output file for test #${test_number} not found (${expected_result_stdout}). Actual test result is below. Manually verify that this output is correct; if so, then copy it to the expected test file path with:\n\n $ cp ${test_result_stdout} ${expected_result_stdout}\n\n------\n${test_result_stdout_actual}\n" + exit 1 + fi + + # Compare the actual output to the expected output. Any discrepency results in test failure. + diff=`diff -u ${expected_result_stdout} ${test_result_stdout}` + if [[ $? != 0 ]]; then + echo -e "Test #${test_number} ${REDB}FAILED${CLR}.\n\n${diff}\n" + exit 1 + fi + + echo -e "Test #${test_number} ${GREEN}passed${CLR}." +} + + +# Instead of spinning up a docker instance, this will run a test using a host on the +# public Internet. +function run_test_internet { + test_number=$1 + command=$2 + + test_result_stdout="${TEST_RESULT_DIR}/test_${test_number}.txt" + expected_result_stdout="docker_test/expected_output/test_${test_number}.txt" + + `/bin/bash -c "${command} | tail -n +3 > ${test_result_stdout}"` + if [[ $? != 0 ]]; then + echo -e "${REDB}Failed to run sslscan! (exit code: $?)${CLR}" + docker container stop -t 0 $cid > /dev/null + exit 1 + fi + + # If the expected output file doesn't exist, give the user all the info we have so they can fix this. + if [[ ! -f ${expected_result_stdout} ]]; then + test_result_stdout_actual=`cat ${test_result_stdout}` + echo -e "\n${REDB}Error:${CLR} expected output file for test #${test_number} not found (${expected_result_stdout}). Actual test result is below. Manually verify that this output is correct; if so, then copy it to the expected test file path with:\n\n $ cp ${test_result_stdout} ${expected_result_stdout}\n\n------\n${test_result_stdout_actual}\n" + exit 1 + fi + + # Compare the actual output to the expected output. Any discrepency results in test failure. + diff=`diff -u ${expected_result_stdout} ${test_result_stdout}` + if [[ $? != 0 ]]; then + echo -e "Test #${test_number} ${REDB}FAILED${CLR}.\n\n${diff}\n" + exit 1 + fi + + echo -e "Test #${test_number} ${GREEN}passed${CLR}." +} + + +# First check if docker is functional. +docker version > /dev/null +if [[ $? != 0 ]]; then + echo -e "${REDB}Error: 'docker version' command failed (error code: $?). Is docker installed and functioning?${CLR}" + exit 1 +fi + +# Make sure sslscan has been built. +if [[ ! -f sslscan ]]; then + echo -e "${REDB}Error: sslscan executable not found. Build it first!${CLR}" + exit 1 +fi + +# If the user specified a test number to debug... +debug_test_number=0 +if [[ $# == 1 ]]; then + debug_test_number=$1 + debug_test_number=$((debug_test_number + 0)) # Effectively, convert this to a number. +fi + +# Check if the docker image is the most up-to-date version. If not, create it. +check_if_docker_image_exists +if [[ $? == 0 ]]; then + echo -e "\n${GREEN}Docker image $IMAGE_NAME:$IMAGE_VERSION already exists.${CLR}" +else + echo -e "\nCreating docker image $IMAGE_NAME:$IMAGE_VERSION..." + create_docker_image + echo -e "\n${GREEN}Done creating docker image!${CLR}" +fi + +# Create a temporary directory to write test results to. +TEST_RESULT_DIR=`mktemp -d /tmp/sslscan_test-results_XXXXXXXXXX` + +# If the user wants to run a specific test with debugging enabled, do that then exit. +if [[ $debug_test_number > 0 ]]; then + eval "run_test_${debug_test_number} 1" + exit 0 +fi + +# Now run all the tests. +echo -e "\nRunning all tests..." +run_tests + +# The test functions above will terminate the script on failure, so if we reached here, +# all tests are successful. +echo -e "\n${GREENB}ALL TESTS PASS!${CLR}\n" + +rm -rf $TEST_RESULT_DIR +exit 0 diff --git a/docker_test/Dockerfile b/docker_test/Dockerfile new file mode 100644 index 0000000..1cbe18a --- /dev/null +++ b/docker_test/Dockerfile @@ -0,0 +1,21 @@ +FROM ubuntu:18.04 + +COPY openssl_prog_v1.0.0 /openssl_v1.0.0/openssl +COPY openssl_prog_v1.0.2 /openssl_v1.0.2/openssl +COPY openssl_prog_v1.1.1 /openssl_v1.1.1/openssl + +# Copy certificates, keys, and DH parameters. +COPY *.pem /etc/ssl/ +COPY *.crt /etc/ssl/ + +# Copy nginx site configurations & modules. +COPY nginx_site_client_cert_required /etc/nginx/sites-available/ +COPY nginx_test9.conf /etc/nginx/ + +# Install nginx for some tests. +# Install strace for potential debugging, and rsyslog to enable system log gathering. +RUN apt update 2> /dev/null +RUN apt install -y nginx strace rsyslog 2> /dev/null +RUN apt clean 2> /dev/null + +EXPOSE 443 diff --git a/docker_test/ca_cert.pem b/docker_test/ca_cert.pem new file mode 100644 index 0000000..3b7ae16 --- /dev/null +++ b/docker_test/ca_cert.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFUTCCAzmgAwIBAgIJAI+xjVeRdKcWMA0GCSqGSIb3DQEBCwUAMD8xCzAJBgNV +BAYTAlhYMR4wHAYDVQQIDBVOb3doZXJlIGluIHBhcnRpY3VsYXIxEDAOBgNVBAcM +B05vd2hlcmUwHhcNMTkxMjAzMDIxNjUzWhcNMjkxMjAzMDIxNjUzWjA/MQswCQYD +VQQGEwJYWDEeMBwGA1UECAwVTm93aGVyZSBpbiBwYXJ0aWN1bGFyMRAwDgYDVQQH +DAdOb3doZXJlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAze8SR6JK +HTftNJrZdnvzE5LlpU6hCVGr1aIhx1nWae7crLRRB7xAc9T+YIMUhMazKwbMJBIx +7I6rYeU+FWJBkcc5AREk0C1sM6vlM001kpcYs3amib1DTJkORdQTJlh5+bPlnupa +YJQIqAVKqnEYUJuOblpeUqz2LteVLlV1hycznrvkmywU72AtzaOTx1hrgH7FjpVz +2M2KJ3zDFO8NfDtqx67fbM8Z/QL+/67tfSFwRKdPU4u38IlushoYbQ/8Y81Hw1tQ +2px08q2awgtFljHl2cDLsDB8bAsQ+AiU9/3trbTid1U48Q8Uk0BBJ+TXio5qDg+n +bPw0gcXlq+Rj8CBADPzWaBZdAtH1kVlSwJ2PZ5xwi0LKNsJN2wbfJIc6WjA/pL5p +VjS+Yx5X8rhGqWAJDrbLoVoTg/bEy8RPPorxBspFe8jPRoSIWsmDZn+SL0SbgnxV +eZG0tVn6nbWepSUOq23Gc9E6sfMsMR3WxBBIchoWCkPB8Y/X0YeT0V3kGql2fVsT +6mMTTDvcc4RORikH+wg0EOmzn+WA0I5BzR2zYANfga+cPuowO+U6qf85wzeO6eDp +x49GAyTCGMYlhZd/hWEXD+Q2bZRy2j8osTRe270MKyYiMuP0eB7VZx7pr1zb8fTE +BAh4JI6xUqCG8isoTyEKDdLrX4ilW+ZN2tkCAwEAAaNQME4wHQYDVR0OBBYEFDTe +OueTIjWF4f771PS5kGNY28BLMB8GA1UdIwQYMBaAFDTeOueTIjWF4f771PS5kGNY +28BLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBALnZCFWzH3n0GFpO +fYxALeoyrwYia4HrGGQ9JOwQJEHH1sUL3TwvGVoLtSB8962loGakvhtwvtr6XDyk +wqsAF9J1j7PKzXvlVt3MAGDupDMTgOvX9D7GY/MYhteB2ExckmDXGyq/Ustm877S +XaEkwiwCs2Jrm9T6ksZIcFd0OwpzfY+sEBjmKKTKo6n0xOmUEvlIsJ8AHZg0cOsj +LD0hdcdwQ6gtvX+LrjrCWk1OzjHlGWLpDuPhDlhYFidBoRH65SWjUzqH6jmaUjEi +pwO3wmPfaXAkSqVw1O+Pkc0BThpSbPCwnn5J6VuAJQN65pLD1vRh0UfpLI8TeOQe +dDDIoiRjRCrBfSmrzZ5uj18fC/MB/6x5jfyPzMMlJCSmpWcuz65imP8VVn8V8M9b +vGM+hgP66xEO4UwBGbKiIWh8Hb0Jqo+vV6AObdpncOmWxnFU891NbyLjgkRfmTMq +dH3q71sarOmvv2aHcZTWwj46mzPoJHViS0lT3XYURTKar16RgMihUmKcMyPdVj75 +JDZyvJwpis3zSPTERmYjeuqY3Lb/hXIWHMg3v6+xWrHunj7aFuugCtyl2qm6uHGh +5uBjZfocr+ZrT4YItUZGsSw4zfkJMIWVuHuX30Q2Gtrkt25IlYCKHZGpb49KyWub +wS03DVRaHGOd/8zksngsXzReZeor +-----END CERTIFICATE----- diff --git a/docker_test/ca_key.pem b/docker_test/ca_key.pem new file mode 100644 index 0000000..d4e80af --- /dev/null +++ b/docker_test/ca_key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDN7xJHokodN+00 +mtl2e/MTkuWlTqEJUavVoiHHWdZp7tystFEHvEBz1P5ggxSExrMrBswkEjHsjqth +5T4VYkGRxzkBESTQLWwzq+UzTTWSlxizdqaJvUNMmQ5F1BMmWHn5s+We6lpglAio +BUqqcRhQm45uWl5SrPYu15UuVXWHJzOeu+SbLBTvYC3No5PHWGuAfsWOlXPYzYon +fMMU7w18O2rHrt9szxn9Av7/ru19IXBEp09Ti7fwiW6yGhhtD/xjzUfDW1DanHTy +rZrCC0WWMeXZwMuwMHxsCxD4CJT3/e2ttOJ3VTjxDxSTQEEn5NeKjmoOD6ds/DSB +xeWr5GPwIEAM/NZoFl0C0fWRWVLAnY9nnHCLQso2wk3bBt8khzpaMD+kvmlWNL5j +HlfyuEapYAkOtsuhWhOD9sTLxE8+ivEGykV7yM9GhIhayYNmf5IvRJuCfFV5kbS1 +WfqdtZ6lJQ6rbcZz0Tqx8ywxHdbEEEhyGhYKQ8Hxj9fRh5PRXeQaqXZ9WxPqYxNM +O9xzhE5GKQf7CDQQ6bOf5YDQjkHNHbNgA1+Br5w+6jA75Tqp/znDN47p4OnHj0YD +JMIYxiWFl3+FYRcP5DZtlHLaPyixNF7bvQwrJiIy4/R4HtVnHumvXNvx9MQECHgk +jrFSoIbyKyhPIQoN0utfiKVb5k3a2QIDAQABAoICAGMM1HwEASXgmoUs3d/xak9F +3pMOKMK0t7O/kgOyoEC/lQC0kizoTQ/pqJh/M8VRVSgi0tmersibLq+ddakPY35c +lnx+5HgFAQAxc8KjJltltYnMTfn+QHp9O7I2eSd+cty5vH4dNm8xhKBcOzeTwiAz +UeSeLrQRYS/SnXx1ulvRbTCyKxi/sSoZ1q4MOa4uRza8wwT7uYbUBdlMVwCgopnY +clmtMOXDDzr0z/XnC2+eP8Olva/vif91+vpLNuhuQfU27Yd3SoJ7snxvJ/qhNU0y +nt2Hr/EEwTOudvD2H8DQMBvW3v6KzSKVIE5bH3uyxEFuknBE80CmZhLtPrTY23/s +97/ncS+tY3mxr8hOBRyiz7o2zDvPcbSq56jt2JkUUS4mwk2uVzpO9uKhrDY9CkkS +Iq5UjV0gtjQ8092Mp83Bazy0q7fTKdwgvsoorbdKMZP4GZ0EPIGJC9r8IH9UD7Cl +1YVGj1qBXUFznbJmFtNGofvc/8PzZ6TMNscEVOcjy8vrqmhKGcdXMoMl1LxDl/4g +mN26n9uKfatCeRN9qyxOsts3+QEqJq+rKn2odQlCNfpezxNh8uauAx8ZxQ4HXirW +O+CZS5JAlNWK5qp27pGq7JNKy5xyaU8PkC5G/A8Fi35iF1o0j2ICSWkCY3cTd73W +/TvzsGNsbrJLTIFfo1ghAoIBAQDqOp7LfXLZct17TdpBSwq+2IzSN/H6ozKcyXSf +Nnx56Avy1OZkU3ELMN+/zZp9X91dhR+PpXJfcbufiuJIUq0L34ow8X+cnw66hUur +ig9rzs7o1Ak6PZcrVINOjZ5Sn6gzuDMZgH5PzFNjXxZto1KjDLCnf5adoYEUfjJZ +r85ZN9/NlUW/PhZzuyRUW0ouRDsjjnLQouomCrFbva2tvpPggCcRlizHg6ReyX1S +LfozmQbfvI4e60cbRj5MuouJbbvMicecRT5R00HhTfHTj5MMqf5DRToS2ir/QYw6 +kZQWHdFih+eDQcZFiPILUxq89OSBJy2UtrfgaFxGiPBdgm5lAoIBAQDhEy5NBB0X +udTc9BJlL/ROp84/ER/OTd4eG57FVXhv/kuC+v2gv/M+PHc7RVSZCh+sEvqs2Dzd +qRms57zQGJ2zbSzhgcCzghpNx+mNXe5UScAUM4sDONOGeeQc15HkAMCz4/umcInc +IcM1zsbxa+AG8YGv9JHuknYBZ2bbaUlsoltQ57sa2h7Wht3ql3IRYSu2hwsWiGlb +MZlozaEXpqH4+LvBfs0gCXNmqMOV72MnEFWFVooSzISi5KakPysH5TNypJpE6FWn +1ccUMTFFkNRFgn64qUXHyaKQlaMl0UPb3XVcyxB4Wamde8yXoo4trdFRGY1kRLl9 +31zFeZDoT8llAoIBAQDGV61wE2LVz/bNGzfeYnVO9oEI4mb+HoQVUGJ5D+KIOH8l +ujL+ccof99sAyFIyKKODNd9r/GXFfMGscCb9p0Tx8PFMULQHJImMWKOjNt2oJRAB +CMxnjRAdmQs30aRnwtrkMO7UgYJ0gEl8tGCBpvOrLmvI6rnX8ZMkj1iDqePKmQ3j +QKw3LZRFnAs/g65lT1Hk4hNHqS0t2ZAmZ5BSuDbwvJRYyBpTOJ5Pxb9hf52HY+X2 +P+z5MbKc3faTcsQGM+37XhCxu9Dx6Tq4VxCYXdPfvXOZ810h6azPSeo9DlmgAM/1 +56+b7m6/IyAThuP1bkqxM0Pd0nwSg0zgTcV86Z4hAoIBAELgYSSPMVnIZMBWYVTh +n9TzNWw12V6Ccpo9mLqHv+Z/B87eZxgpkMwQSVk6K33hrTGC3isXgVZXlYJzxP2M +Iueaa/iBhlGQOeKcoP/ZRiSTWVhnTEnjy64sb6RGRVobAycweailzcCz434Md75q +UEGf5unyYJ4jtJ6MK9rL+P4na7ypbkX3Q6x4nF3FLCaP2d49WAUU+UEYhr3GQ7R0 +VbJVrew7khWP2VNKl/roC20jBFY/NX2KeWqxR/aLsmyBJP1OfWw2IKVi9ulACKTj ++L7CnIaf/VT0y7HsVHK7ME+XCPVOfRFVivl5PHxd16Mo/4X6crG1XexRvw4KJg1x +D6UCggEAT+eKtfA0EkA4zQKAC15KZSTxrpYK0phQX6dBTgwXlwoczInlX7HjtQb9 +7G9OzRFZvenzXsBfT+av1ilSjEPo6l/bL664qJY4hzG+5Tq1NC0YA+2Ihb9/wQP/ +yXp/tnn27XZChm/wxdGG+s7wpWaZ9LQj/80pbMbH/DoMGlaFyHF+8RPXbDF6ycJF +kAV9E0PKeVBGaQbvEx1NW093F1Lf2yPhPeEA89qjmOigyZQ7r4tIhJxYgzUo3gqD +b8PbWwbrGPGD5AUu6V4Fv2E86mIgoRlcZFayHGDvGSqM5CZ7VSLLc9pc33WPV55T +IvfsnBvVJ9M2TPyXcd9tejBOzLjOkQ== +-----END PRIVATE KEY----- diff --git a/docker_test/cert_1024.crt b/docker_test/cert_1024.crt new file mode 100644 index 0000000..a9da5ce --- /dev/null +++ b/docker_test/cert_1024.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDpDCCAYwCCQCaM8BbiyPRSTANBgkqhkiG9w0BAQsFADA/MQswCQYDVQQGEwJY +WDEeMBwGA1UECAwVTm93aGVyZSBpbiBwYXJ0aWN1bGFyMRAwDgYDVQQHDAdOb3do +ZXJlMB4XDTE5MTIwMzAzNTY1MloXDTI5MTIwMzAzNTY1MlowbTELMAkGA1UEBhMC +VVMxCzAJBgNVBAgMAk5ZMRIwEAYDVQQHDAlSb2NoZXN0ZXIxGTAXBgNVBAoMEEJh +bWJvb3psZWQsIEluYy4xIjAgBgNVBAMMGWhvd2Z1Y2tlZGlzbXlkYXRhYmFzZS5j +b20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOak+uYE1LeCoKAIH2Uq8fhm +lf0W8fPDc/iQ1vI3jn7zKruAFSl/0lgVA7SuqbSFJ5slJBQOSGsV87qidl2wzI3f +aU+VU8WYEgswE+BrElNVQ5r5NbGDJW4+Bp+2sxAyvRa+Fu/7deG3mGo9MQp78YTD +Fcko9KbYXUCACSTCVBHNAgMBAAEwDQYJKoZIhvcNAQELBQADggIBAEh3v+b8P6/g +3OkAzkNpLJ2yQK1AJ35yd9KtmnTWzAYfWqkowWOZPVQv41VG0LEy8DF/DuBlXLyp +H1HfY7hpJYMmZfs1Mdcr1D7pir1nobG7CFJSiS4/R1Irqb4KQhFaYPEvdy6vEh5s +T+DrF6/rWlE1QnoiAoDxgUn7gYv5LThux/aX2L9ne6YY8mxBZm6AXCjsXGSFZdFY +vAFeQTAVs6/lJ5AXrV9IIO5L9MGozeKVKTwz5MqNlQjr2XkGeCJ/+L40NL91/mTK +xuSIZXP3gCyfL+szN7qQ8NWmrqdFoUkzVyV+SUbXfpuVLf+yC7dZGZx8AktqQERr +esKgd54fIJTpZGRtx/y9UW9OAHugAoAd/6Sd1Pk3B2YH4cJPFQTUkod4OKotWs0f +R4DA+aAf0tqFwKRTGDsny/6+nnGenn75zRunmae0R51vS4vbHgEoMVsGLu/QbSdC ++f9DYXpeH96u/0lKl5ueW/Acoa20ngJFS6IzJiWMTJPxWJYq+gOnSMS2OEakoUKU +UYjZ1VFYJrnXB+cKBksY38c6ryskUP1dfaWICwX9DH2MnD1RuuaKcdmhu+k45ujC +LefUCIQ+2K4jMe/Irvk9yAbKfSBZ7xfRfgNPTdr0jjLfSZHhI5QDUOUsP8SEt1yV +CQx1WMxnRCNtwJVsAhisGWFTA0sDImOX +-----END CERTIFICATE----- diff --git a/docker_test/cert_2048.crt b/docker_test/cert_2048.crt new file mode 100644 index 0000000..f671473 --- /dev/null +++ b/docker_test/cert_2048.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEKTCCAhECCQCaM8BbiyPRSDANBgkqhkiG9w0BAQsFADA/MQswCQYDVQQGEwJY +WDEeMBwGA1UECAwVTm93aGVyZSBpbiBwYXJ0aWN1bGFyMRAwDgYDVQQHDAdOb3do +ZXJlMB4XDTE5MTIwMzAzMDEyM1oXDTI5MTIwMzAzMDEyM1owbjELMAkGA1UEBhMC +VVMxCzAJBgNVBAgMAk5ZMRIwEAYDVQQHDAlSb2NoZXN0ZXIxGTAXBgNVBAoMEEJh +bWJvb3psZWQsIEluYy4xIzAhBgNVBAMMGndoeXRoZWZ1Y2t3YXNpYnJlYWNoZWQu +Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAywGmJp/AoA4TCs6z +bXuiBOkho35IeVvpsy7RqM3y3KxkEFnk/LM6U/ayL+j2vo4/15WPM0PaAGRRbvnQ +EuI1xvhn/0/T4xP+TBe91pTMo/nKrK/ycvBLBqLPZQK9SJbHk6mwfgpQs5S/+VHl +U9jl7+eQWcR+o3NXtv4XFlQyqx1dcokAJrL4wr2vGPkigUNU2iI6FwRB4f7Wo1rB +NzI49uE97IWuh+VBMPYMp+Zn2Om4ptCyjdvSI7DEYc6jyKlPzH2UOgd0RkcwivaS +pxfXJEBOC8PtOxyLg/KPjUTwUh0nHSpeOIbT3HKnOErEbbiHQmlYbbcOyinv3hIl +Rj+PyQIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQCYTQPx8JIdeNfov2cSsM/8ByDo +M6DDhW+kAgGdhKdGglDXtrtX4ffPYvG1EjQg7TIZJoXWcwng4XWGFI7lGqyAOQn9 +KjDqfFj00udNJq8B57JJK3vq71rppcggt5mJnzTrrMlTZ4z8ZMFLnj6drCEsjZLM +3oRRcBvtfC4j9xT4ZICt8R3eXw18Ne43PT1wRhFpQAud0Y9zPO/0veyAlf/D0suR +8Ix8XXRr3PU+c5XZeY2uT50FcHNKLgcSmck+25CPnwSdQtdhhfcXGpBKzczjHHTU +yqIBVf9xwM4sCtg50aWrdYTYgFivMqPy4ieLe/NlhrlmjSJPFR/hw7605mTiu4zG +9Dlr310eCjL8jiASWpfj27u6QYaxFL5yg1mMfl/mvDr9dLV4LnffdkeE8hk+PVkz +IvHKeLhAu39t1JAs841NwW0WhdxOQkSB+VqDmixy9lmJhM0c8I45S9qERvnKrd9S +kMiVxO0d4Aza1eEt1Kep2tfK2CkAzQD30Tl/v4njPZXR7lU5p4g6pr4EukxBwMrs +t2Hs1Czb9x59HV7FDB0Z8DgrNkysi40lRMMNzNoQ2HaoaLKuotwXZFCs5O5HRnze +iMDS3Jy0gDs53TanmxXC2gE/ODeYOqzkOjvGgPruZOMEZ7bKkLkC/lcUxIYy4xoE +PgE/onpOVIay+K/3dQ== +-----END CERTIFICATE----- diff --git a/docker_test/cert_3072.crt b/docker_test/cert_3072.crt new file mode 100644 index 0000000..abd27be --- /dev/null +++ b/docker_test/cert_3072.crt @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEmTCCAoECCQCaM8BbiyPRSjANBgkqhkiG9w0BAQsFADA/MQswCQYDVQQGEwJY +WDEeMBwGA1UECAwVTm93aGVyZSBpbiBwYXJ0aWN1bGFyMRAwDgYDVQQHDAdOb3do +ZXJlMB4XDTE5MTIwMzA0MDc0M1oXDTI5MTIwMzA0MDc0M1owXjELMAkGA1UEBhMC +VVMxCzAJBgNVBAgMAk5ZMRIwEAYDVQQHDAlSb2NoZXN0ZXIxGTAXBgNVBAoMEEJh +bWJvb3psZWQsIEluYy4xEzARBgNVBAMMCmxtZ3RmeS5jb20wggGiMA0GCSqGSIb3 +DQEBAQUAA4IBjwAwggGKAoIBgQDEDVOhDYctVgOYpKM9KUKmixtQxgDfQGVFczN0 +l7U5UGD+rASuFRGUUC8YX2WOBcWcxnqhMrXriwlexyM1dL8BupY72sF4xtTEPzn8 +9Gjh6aYFWKh7kD8DjFsC8+3WyfCCNu1k1OzFmiF5SjHbXr81MnbhzdIYQE6UBIEe +1PpUEk9qbHVoAuVKVLiOq0sCWTHPoz9dQ95ERHoMphdSLfvDRcJlFGTVTa54zad+ +TPjtr8bGh4Baa9Y9VbUG75Vslv0eyH/ai3KEdkBVf39+wpnAd/2pxKu60uTkzSLH +01QWeryplW5ktNlrv+sLDpieaU6/WYBknyw0m23XDKEwYt5uR9UcoREKqTfstGlL +OWhO73n64+7+r7f3VcwpM6YwerCG9kGkCg683tuzijw3UkXyE+74wEaxlSzw/571 +ZMlTb3O85FZ3tn/wrXNqSKEkP0VdwLfw4Y7zyH/slXFhwzJVRlbfNkrEhOUlaXwn +Xw6pClProrhx4s5bVKNEh4cZf1MCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAikFI +8LMptJKl9L5WmXW3OFS/stc0dxBQ/0/qzPiDWrhINrFkIYeNZ2fi+Cv6mLXil+C1 +72Mu9YsTJ6L6VjHUnIXAhwQC4gjnhjPoZIQ3sdaQl0I5vwPr5xS6wDLoWtUSjcem +x8x+axPEsqw/EIGv55NsY7YezpqFU48rkRrGbJL9jOVbKcIwzbg5ZxqRZ2kmSUD9 +Ze56RqXhwZPbdMmcrIk2632RoAh9HXgndL9QCIvypDnK50KpP/b2C/1Amaux//Rs +ro8C55J/x2FWl0iDwHc4gAtsZvn8aznfGnavj4JHq8+3cZBZQ3zfv6ojFvWCBniT +YGb57CJA+s1MW2urF6ldExgsb/adQN7oXW6I0Y9A+zFOdd3epoa+GJZu2FI7kVs3 +VViioCRPDCCxgDJ8CnhBvr5ALd+dWDGOpU7+POWqmtscF56tnPgiCK9J8TsT2GkN +S5h/NbTbxEZvFAJS5x4GnwQBW0o0tmnybLzkRUeUucDg3k/jsMsnQIft2kPtcxD8 +vEZWKl/jwfX6EMLIXgAHIDK2HiG9301GlksvDTFaZhMNRcH9RYhTwYYsdLjvs5Bj +aY+evRF2E6MQnaLQ7m1Hg8YZZY5O3Z/n6fPUESd3zMSsXtmcyRZ4KP5LSwTy6HuE ++qEu3vdeFaOd+Ii8k8sD/4SuKf7RcXC3OG5Ne0M= +-----END CERTIFICATE----- diff --git a/docker_test/dhparams_1024.pem b/docker_test/dhparams_1024.pem new file mode 100644 index 0000000..5fbcf87 --- /dev/null +++ b/docker_test/dhparams_1024.pem @@ -0,0 +1,5 @@ +-----BEGIN DH PARAMETERS----- +MIGHAoGBAOA34y/7fH82VEhOGbr50PFlSTZcVG5+YtJmVsWH+r6Y72UAIyhBbF2D +ll4gK+uYmXam6Uk8Nwf1U4QiLf7H6ZWlk3ynTa0XUWAGDf8Fce/Y9bWaJV+M7Klr +c+WGk/Rt8CySRfB58fzsoGuDEW85tq5rqlkJcIKBr2bgSTtE8kIrAgEC +-----END DH PARAMETERS----- diff --git a/docker_test/dhparams_2048.pem b/docker_test/dhparams_2048.pem new file mode 100644 index 0000000..8d29550 --- /dev/null +++ b/docker_test/dhparams_2048.pem @@ -0,0 +1,8 @@ +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEAhmyrz3SekFJY9nkmUt7tKXi/fNfxw3/UZA9+g0SOsvYxMI+vw8XJ +ILm+8HJR5+kvcz6vkxgbxV9IACEdRzf33zBHcRXzA7OifsAy8CN217d8HNHqurGk +ueCLTn2w1SfMy2Do3NB50AOru32xPBQL9hqLLhqEs8IKdAVuNL/OKmuLCovaAck4 +YYCT0Phe6VSmOmMP46dFJYuAIoup6J/TsDLqGIG/G8bZPaAn1XtgjJ23Ptoielu1 +z7CcvO2Bxv5gDGUnd/oW+rWU1gJ2Aav62564Fy6tNSVnNWzWy3WGuqMjkzJsEy8L +3sklLhryd4vf1E2vvFRaupMUY9g0oVWB4wIBAg== +-----END DH PARAMETERS----- diff --git a/docker_test/dhparams_3072.pem b/docker_test/dhparams_3072.pem new file mode 100644 index 0000000..5a7c699 --- /dev/null +++ b/docker_test/dhparams_3072.pem @@ -0,0 +1,11 @@ +-----BEGIN DH PARAMETERS----- +MIIBiAKCAYEAjoI7ICm70zsvw1DgmheGKxrpFz31cR2F+b4P5HwFPJ77EZDDNZQ2 +rmfJ6B1F4fFZZcGeEzuRvnujzy3grie33zRDvPLAFSzoTWjarh/bEiMcDFz/X2AY +7TAlC1snEmdcrnar8H7Twg2pWCbUKrwF/wsBsqjzXtokGqhseUTDgTUjP4JW94li +3SnqBPLGypFPGmwt5rq6IUARilOXHhwDfodV2JHvbdRvbIUivShYT9YpzLwA512s +sz4clyLNjFDpVdX9HtcQoJL7etStC8Jo7qJvpjkQUGxUrbZR7QM12YfHiT7+dOIi +PyLPGrEm11FWLntxyX+RuR8v5wVaXIiRziwRiz/xy4YM5giYXPQFSWNcSp7YlZO2 +8LyTreyWKp9hHPFN0B2PX1G5XU8bEsIeS/gUVorjd/k6/KsQGHhFpUTMAv43CgYI +UVXqw8DPGQKHejfmA5sX3rKTXZlxQjKofxsZUuymuH+Bn9tQKCLzFVWPMScM0Abb +xNG5W9qEvHGDAgEC +-----END DH PARAMETERS----- diff --git a/docker_test/expected_output/test_1.txt b/docker_test/expected_output/test_1.txt new file mode 100644 index 0000000..81b9db2 --- /dev/null +++ b/docker_test/expected_output/test_1.txt @@ -0,0 +1,102 @@ + +Connected to 127.0.0.1 + +Testing SSL server localhost on port 4443 using SNI name localhost + + TLS Fallback SCSV: +Server supports TLS Fallback SCSV + + TLS renegotiation: +Secure session renegotiation supported + + TLS Compression: +Compression enabled (CRIME) + + Heartbleed: +TLS 1.3 not vulnerable to heartbleed +TLS 1.2 not vulnerable to heartbleed +TLS 1.1 not vulnerable to heartbleed +TLS 1.0 not vulnerable to heartbleed + + SSL Protocols: +SSLv2 is not enabled +SSLv3 is enabled + + Supported Server Cipher(s): +Preferred TLSv1.2 256 bits ECDHE-RSA-AES256-GCM-SHA384  Curve P-256 DHE 256 +Accepted TLSv1.2 256 bits DHE-RSA-AES256-GCM-SHA384  DHE 2048 bits +Accepted TLSv1.2 128 bits ECDHE-RSA-AES128-GCM-SHA256  Curve P-256 DHE 256 +Accepted TLSv1.2 128 bits DHE-RSA-AES128-GCM-SHA256  DHE 2048 bits +Accepted TLSv1.2 256 bits ECDHE-RSA-AES256-SHA384 Curve P-256 DHE 256 +Accepted TLSv1.2 256 bits DHE-RSA-AES256-SHA256 DHE 2048 bits +Accepted TLSv1.2 128 bits ECDHE-RSA-AES128-SHA256 Curve P-256 DHE 256 +Accepted TLSv1.2 128 bits DHE-RSA-AES128-SHA256 DHE 2048 bits +Accepted TLSv1.2 256 bits ECDHE-RSA-AES256-SHA Curve P-256 DHE 256 +Accepted TLSv1.2 256 bits DHE-RSA-AES256-SHA DHE 2048 bits +Accepted TLSv1.2 256 bits DHE-RSA-CAMELLIA256-SHA DHE 2048 bits +Accepted TLSv1.2 128 bits ECDHE-RSA-AES128-SHA Curve P-256 DHE 256 +Accepted TLSv1.2 128 bits DHE-RSA-AES128-SHA DHE 2048 bits +Accepted TLSv1.2 128 bits DHE-RSA-SEED-SHA DHE 2048 bits +Accepted TLSv1.2 128 bits DHE-RSA-CAMELLIA128-SHA DHE 2048 bits +Accepted TLSv1.2 128 bits ECDHE-RSA-RC4-SHA  Curve P-256 DHE 256 +Accepted TLSv1.2 112 bits ECDHE-RSA-DES-CBC3-SHA  Curve P-256 DHE 256 +Accepted TLSv1.2 112 bits DHE-RSA-DES-CBC3-SHA  DHE 2048 bits +Accepted TLSv1.2 256 bits AES256-GCM-SHA384 +Accepted TLSv1.2 128 bits AES128-GCM-SHA256 +Accepted TLSv1.2 256 bits AES256-SHA256 +Accepted TLSv1.2 128 bits AES128-SHA256 +Accepted TLSv1.2 256 bits AES256-SHA +Accepted TLSv1.2 256 bits CAMELLIA256-SHA +Accepted TLSv1.2 128 bits AES128-SHA +Accepted TLSv1.2 128 bits SEED-SHA +Accepted TLSv1.2 128 bits CAMELLIA128-SHA +Accepted TLSv1.2 128 bits RC4-SHA  +Accepted TLSv1.2 128 bits RC4-MD5  +Accepted TLSv1.2 112 bits DES-CBC3-SHA  +Preferred TLSv1.1 256 bits ECDHE-RSA-AES256-SHA Curve P-256 DHE 256 +Accepted TLSv1.1 256 bits DHE-RSA-AES256-SHA DHE 2048 bits +Accepted TLSv1.1 256 bits DHE-RSA-CAMELLIA256-SHA DHE 2048 bits +Accepted TLSv1.1 128 bits ECDHE-RSA-AES128-SHA Curve P-256 DHE 256 +Accepted TLSv1.1 128 bits DHE-RSA-AES128-SHA DHE 2048 bits +Accepted TLSv1.1 128 bits DHE-RSA-SEED-SHA DHE 2048 bits +Accepted TLSv1.1 128 bits DHE-RSA-CAMELLIA128-SHA DHE 2048 bits +Accepted TLSv1.1 128 bits ECDHE-RSA-RC4-SHA  Curve P-256 DHE 256 +Accepted TLSv1.1 112 bits ECDHE-RSA-DES-CBC3-SHA  Curve P-256 DHE 256 +Accepted TLSv1.1 112 bits DHE-RSA-DES-CBC3-SHA  DHE 2048 bits +Accepted TLSv1.1 256 bits AES256-SHA +Accepted TLSv1.1 256 bits CAMELLIA256-SHA +Accepted TLSv1.1 128 bits AES128-SHA +Accepted TLSv1.1 128 bits SEED-SHA +Accepted TLSv1.1 128 bits CAMELLIA128-SHA +Accepted TLSv1.1 128 bits IDEA-CBC-SHA +Accepted TLSv1.1 128 bits RC4-SHA  +Accepted TLSv1.1 128 bits RC4-MD5  +Accepted TLSv1.1 112 bits DES-CBC3-SHA  +Preferred TLSv1.0 256 bits ECDHE-RSA-AES256-SHA Curve P-256 DHE 256 +Accepted TLSv1.0 256 bits DHE-RSA-AES256-SHA DHE 2048 bits +Accepted TLSv1.0 256 bits DHE-RSA-CAMELLIA256-SHA DHE 2048 bits +Accepted TLSv1.0 128 bits ECDHE-RSA-AES128-SHA Curve P-256 DHE 256 +Accepted TLSv1.0 128 bits DHE-RSA-AES128-SHA DHE 2048 bits +Accepted TLSv1.0 128 bits DHE-RSA-SEED-SHA DHE 2048 bits +Accepted TLSv1.0 128 bits DHE-RSA-CAMELLIA128-SHA DHE 2048 bits +Accepted TLSv1.0 128 bits ECDHE-RSA-RC4-SHA  Curve P-256 DHE 256 +Accepted TLSv1.0 112 bits ECDHE-RSA-DES-CBC3-SHA  Curve P-256 DHE 256 +Accepted TLSv1.0 112 bits DHE-RSA-DES-CBC3-SHA  DHE 2048 bits +Accepted TLSv1.0 256 bits AES256-SHA +Accepted TLSv1.0 256 bits CAMELLIA256-SHA +Accepted TLSv1.0 128 bits AES128-SHA +Accepted TLSv1.0 128 bits SEED-SHA +Accepted TLSv1.0 128 bits CAMELLIA128-SHA +Accepted TLSv1.0 128 bits IDEA-CBC-SHA +Accepted TLSv1.0 128 bits RC4-SHA  +Accepted TLSv1.0 128 bits RC4-MD5  +Accepted TLSv1.0 112 bits DES-CBC3-SHA  + + SSL Certificate: +Signature Algorithm: sha256WithRSAEncryption +RSA Key Strength: 2048 + +Subject: whythefuckwasibreached.com +Issuer: /C=XX/ST=Nowhere in particular/L=Nowhere +Not valid before: Dec 3 03:01:23 2019 GMT +Not valid after: Dec 3 03:01:23 2029 GMT diff --git a/docker_test/expected_output/test_10.txt b/docker_test/expected_output/test_10.txt new file mode 100644 index 0000000..9140682 --- /dev/null +++ b/docker_test/expected_output/test_10.txt @@ -0,0 +1,20 @@ + +Connected to 127.0.0.1 + +Testing SSL server localhost on port 4443 using SNI name localhost + + SSL Protocols: +SSLv2 is not enabled +SSLv3 is not enabled + + Supported Server Cipher(s): +Preferred 400 Bad Request TLSv1.2 256 bits ECDHE-RSA-CHACHA20-POLY1305  Curve 25519 DHE 253 + + SSL Certificate: +Signature Algorithm: sha256WithRSAEncryption +RSA Key Strength: 3072 + +Subject: lmgtfy.com +Issuer: /C=XX/ST=Nowhere in particular/L=Nowhere +Not valid before: Dec 3 04:07:43 2019 GMT +Not valid after: Dec 3 04:07:43 2029 GMT diff --git a/docker_test/expected_output/test_11.txt b/docker_test/expected_output/test_11.txt new file mode 100644 index 0000000..6e2619a --- /dev/null +++ b/docker_test/expected_output/test_11.txt @@ -0,0 +1,21 @@ + +Connected to + +Testing SSL server www.amazon.com on port 443 using SNI name www.amazon.com + + OCSP Stapling Request: +OCSP Response Status: successful (0x0) +Response Type: Basic OCSP Response +Version: 1 (0x0) +Responder Id: +Produced At: +Responses: + Certificate ID: + Hash Algorithm: + Issuer Name Hash: + Issuer Key Hash: + Serial Number: + Cert Status: good + This Update: + Next Update: + diff --git a/docker_test/expected_output/test_2.txt b/docker_test/expected_output/test_2.txt new file mode 100644 index 0000000..d2814ca --- /dev/null +++ b/docker_test/expected_output/test_2.txt @@ -0,0 +1,27 @@ + +Connected to 127.0.0.1 + +Testing SSL server localhost on port 4443 using SNI name localhost + + TLS Fallback SCSV: +Connection failed - unable to determine TLS Fallback SCSV support + + TLS renegotiation: +Session renegotiation not supported + + TLS Compression: +Compression disabled + + Heartbleed: +TLS 1.3 not vulnerable to heartbleed +TLS 1.2 not vulnerable to heartbleed +TLS 1.1 not vulnerable to heartbleed +TLS 1.0 not vulnerable to heartbleed + + SSL Protocols: +SSLv2 is enabled +SSLv3 is not enabled + + Supported Server Cipher(s): +Certificate information cannot be enumerated through SSLv2 nor SSLv3. + diff --git a/docker_test/expected_output/test_3.txt b/docker_test/expected_output/test_3.txt new file mode 100644 index 0000000..94de8b9 --- /dev/null +++ b/docker_test/expected_output/test_3.txt @@ -0,0 +1,27 @@ + +Connected to 127.0.0.1 + +Testing SSL server localhost on port 4443 using SNI name localhost + + TLS Fallback SCSV: +Connection failed - unable to determine TLS Fallback SCSV support + + TLS renegotiation: +Session renegotiation not supported + + TLS Compression: +Compression disabled + + Heartbleed: +TLS 1.3 not vulnerable to heartbleed +TLS 1.2 not vulnerable to heartbleed +TLS 1.1 not vulnerable to heartbleed +TLS 1.0 not vulnerable to heartbleed + + SSL Protocols: +SSLv2 is not enabled +SSLv3 is enabled + + Supported Server Cipher(s): +Certificate information cannot be enumerated through SSLv2 nor SSLv3. + diff --git a/docker_test/expected_output/test_4.txt b/docker_test/expected_output/test_4.txt new file mode 100644 index 0000000..d6d6c4c --- /dev/null +++ b/docker_test/expected_output/test_4.txt @@ -0,0 +1,69 @@ + +Connected to 127.0.0.1 + +Testing SSL server localhost on port 4443 using SNI name localhost + + TLS Fallback SCSV: +Server supports TLS Fallback SCSV + + TLS renegotiation: +Secure session renegotiation supported + + TLS Compression: +Compression disabled + + Heartbleed: +TLS 1.3 not vulnerable to heartbleed +TLS 1.2 not vulnerable to heartbleed +TLS 1.1 not vulnerable to heartbleed +TLS 1.0 not vulnerable to heartbleed + + SSL Protocols: +SSLv2 is not enabled +SSLv3 is not enabled + + Supported Server Cipher(s): +Preferred TLSv1.3 128 bits TLS_AES_128_GCM_SHA256 Curve 25519 DHE 253 +Accepted TLSv1.3 256 bits TLS_AES_256_GCM_SHA384 Curve 25519 DHE 253 +Accepted TLSv1.3 256 bits TLS_CHACHA20_POLY1305_SHA256 Curve 25519 DHE 253 +Preferred TLSv1.2 256 bits ECDHE-RSA-AES256-GCM-SHA384  Curve 25519 DHE 253 +Accepted TLSv1.2 256 bits DHE-RSA-AES256-GCM-SHA384  DHE 3072 bits +Accepted TLSv1.2 256 bits ECDHE-RSA-CHACHA20-POLY1305  Curve 25519 DHE 253 +Accepted TLSv1.2 256 bits DHE-RSA-CHACHA20-POLY1305  DHE 3072 bits +Accepted TLSv1.2 128 bits ECDHE-RSA-AES128-GCM-SHA256  Curve 25519 DHE 253 +Accepted TLSv1.2 128 bits DHE-RSA-AES128-GCM-SHA256  DHE 3072 bits +Accepted TLSv1.2 256 bits ECDHE-RSA-AES256-SHA384 Curve 25519 DHE 253 +Accepted TLSv1.2 256 bits DHE-RSA-AES256-SHA256 DHE 3072 bits +Accepted TLSv1.2 128 bits ECDHE-RSA-AES128-SHA256 Curve 25519 DHE 253 +Accepted TLSv1.2 128 bits DHE-RSA-AES128-SHA256 DHE 3072 bits +Accepted TLSv1.2 256 bits ECDHE-RSA-AES256-SHA Curve 25519 DHE 253 +Accepted TLSv1.2 256 bits DHE-RSA-AES256-SHA DHE 3072 bits +Accepted TLSv1.2 128 bits ECDHE-RSA-AES128-SHA Curve 25519 DHE 253 +Accepted TLSv1.2 128 bits DHE-RSA-AES128-SHA DHE 3072 bits +Accepted TLSv1.2 256 bits AES256-GCM-SHA384 +Accepted TLSv1.2 128 bits AES128-GCM-SHA256 +Accepted TLSv1.2 256 bits AES256-SHA256 +Accepted TLSv1.2 128 bits AES128-SHA256 +Accepted TLSv1.2 256 bits AES256-SHA +Accepted TLSv1.2 128 bits AES128-SHA +Preferred TLSv1.1 256 bits ECDHE-RSA-AES256-SHA Curve 25519 DHE 253 +Accepted TLSv1.1 256 bits DHE-RSA-AES256-SHA DHE 3072 bits +Accepted TLSv1.1 128 bits ECDHE-RSA-AES128-SHA Curve 25519 DHE 253 +Accepted TLSv1.1 128 bits DHE-RSA-AES128-SHA DHE 3072 bits +Accepted TLSv1.1 256 bits AES256-SHA +Accepted TLSv1.1 128 bits AES128-SHA +Preferred TLSv1.0 256 bits ECDHE-RSA-AES256-SHA Curve 25519 DHE 253 +Accepted TLSv1.0 256 bits DHE-RSA-AES256-SHA DHE 3072 bits +Accepted TLSv1.0 128 bits ECDHE-RSA-AES128-SHA Curve 25519 DHE 253 +Accepted TLSv1.0 128 bits DHE-RSA-AES128-SHA DHE 3072 bits +Accepted TLSv1.0 256 bits AES256-SHA +Accepted TLSv1.0 128 bits AES128-SHA + + SSL Certificate: +Signature Algorithm: sha256WithRSAEncryption +RSA Key Strength: 3072 + +Subject: lmgtfy.com +Issuer: /C=XX/ST=Nowhere in particular/L=Nowhere +Not valid before: Dec 3 04:07:43 2019 GMT +Not valid after: Dec 3 04:07:43 2029 GMT diff --git a/docker_test/expected_output/test_5.txt b/docker_test/expected_output/test_5.txt new file mode 100644 index 0000000..1c54738 --- /dev/null +++ b/docker_test/expected_output/test_5.txt @@ -0,0 +1,157 @@ + +Connected to 127.0.0.1 + +Testing SSL server localhost on port 4443 using SNI name localhost + + TLS Fallback SCSV: +Server supports TLS Fallback SCSV + + TLS renegotiation: +Secure session renegotiation supported + + TLS Compression: +Compression enabled (CRIME) + + Heartbleed: +TLS 1.3 not vulnerable to heartbleed +TLS 1.2 not vulnerable to heartbleed +TLS 1.1 not vulnerable to heartbleed +TLS 1.0 not vulnerable to heartbleed + + SSL Protocols: +SSLv2 is not enabled +SSLv3 is enabled + + Supported Server Cipher(s): +Preferred TLSv1.2 256 bits ECDHE-RSA-AES256-GCM-SHA384  Curve P-256 DHE 256 +Accepted TLSv1.2 256 bits DHE-RSA-AES256-GCM-SHA384  DHE 1024 bits +Accepted TLSv1.2 256 bits ADH-AES256-GCM-SHA384  DHE 1024 bits +Accepted TLSv1.2 128 bits ECDHE-RSA-AES128-GCM-SHA256  Curve P-256 DHE 256 +Accepted TLSv1.2 128 bits DHE-RSA-AES128-GCM-SHA256  DHE 1024 bits +Accepted TLSv1.2 128 bits ADH-AES128-GCM-SHA256  DHE 1024 bits +Accepted TLSv1.2 256 bits ECDHE-RSA-AES256-SHA384 Curve P-256 DHE 256 +Accepted TLSv1.2 256 bits DHE-RSA-AES256-SHA256 DHE 1024 bits +Accepted TLSv1.2 256 bits ADH-AES256-SHA256  DHE 1024 bits +Accepted TLSv1.2 128 bits ECDHE-RSA-AES128-SHA256 Curve P-256 DHE 256 +Accepted TLSv1.2 128 bits DHE-RSA-AES128-SHA256 DHE 1024 bits +Accepted TLSv1.2 128 bits ADH-AES128-SHA256  DHE 1024 bits +Accepted TLSv1.2 256 bits ECDHE-RSA-AES256-SHA Curve P-256 DHE 256 +Accepted TLSv1.2 256 bits DHE-RSA-AES256-SHA DHE 1024 bits +Accepted TLSv1.2 256 bits DHE-RSA-CAMELLIA256-SHA DHE 1024 bits +Accepted TLSv1.2 256 bits AECDH-AES256-SHA  Curve P-256 DHE 256 +Accepted TLSv1.2 256 bits ADH-AES256-SHA  DHE 1024 bits +Accepted TLSv1.2 256 bits ADH-CAMELLIA256-SHA  DHE 1024 bits +Accepted TLSv1.2 128 bits ECDHE-RSA-AES128-SHA Curve P-256 DHE 256 +Accepted TLSv1.2 128 bits DHE-RSA-AES128-SHA DHE 1024 bits +Accepted TLSv1.2 128 bits DHE-RSA-SEED-SHA DHE 1024 bits +Accepted TLSv1.2 128 bits DHE-RSA-CAMELLIA128-SHA DHE 1024 bits +Accepted TLSv1.2 128 bits AECDH-AES128-SHA  Curve P-256 DHE 256 +Accepted TLSv1.2 128 bits ADH-AES128-SHA  DHE 1024 bits +Accepted TLSv1.2 128 bits ADH-SEED-SHA  DHE 1024 bits +Accepted TLSv1.2 128 bits ADH-CAMELLIA128-SHA  DHE 1024 bits +Accepted TLSv1.2 128 bits ECDHE-RSA-RC4-SHA  Curve P-256 DHE 256 +Accepted TLSv1.2 128 bits AECDH-RC4-SHA  Curve P-256 DHE 256 +Accepted TLSv1.2 128 bits ADH-RC4-MD5  DHE 1024 bits +Accepted TLSv1.2 112 bits ECDHE-RSA-DES-CBC3-SHA  Curve P-256 DHE 256 +Accepted TLSv1.2 112 bits DHE-RSA-DES-CBC3-SHA  DHE 1024 bits +Accepted TLSv1.2 112 bits AECDH-DES-CBC3-SHA  Curve P-256 DHE 256 +Accepted TLSv1.2 112 bits ADH-DES-CBC3-SHA  DHE 1024 bits +Accepted TLSv1.2 256 bits AES256-GCM-SHA384 +Accepted TLSv1.2 128 bits AES128-GCM-SHA256 +Accepted TLSv1.2 256 bits AES256-SHA256 +Accepted TLSv1.2 128 bits AES128-SHA256 +Accepted TLSv1.2 256 bits AES256-SHA +Accepted TLSv1.2 256 bits CAMELLIA256-SHA +Accepted TLSv1.2 128 bits AES128-SHA +Accepted TLSv1.2 128 bits SEED-SHA +Accepted TLSv1.2 128 bits CAMELLIA128-SHA +Accepted TLSv1.2 128 bits RC4-SHA  +Accepted TLSv1.2 128 bits RC4-MD5  +Accepted TLSv1.2 112 bits DES-CBC3-SHA  +Accepted TLSv1.2 40 bits TLS_RSA_EXPORT_WITH_RC4_40_MD5 +Accepted TLSv1.2 40 bits TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 +Accepted TLSv1.2 40 bits TLS_RSA_EXPORT_WITH_DES40_CBC_SHA +Accepted TLSv1.2 56 bits TLS_RSA_WITH_DES_CBC_SHA  +Accepted TLSv1.2 56 bits TLS_DHE_RSA_WITH_DES_CBC_SHA  +Accepted TLSv1.2 56 bits TLS_DH_anon_WITH_DES_CBC_SHA  +Preferred TLSv1.1 256 bits ECDHE-RSA-AES256-SHA Curve P-256 DHE 256 +Accepted TLSv1.1 256 bits DHE-RSA-AES256-SHA DHE 1024 bits +Accepted TLSv1.1 256 bits DHE-RSA-CAMELLIA256-SHA DHE 1024 bits +Accepted TLSv1.1 256 bits AECDH-AES256-SHA  Curve P-256 DHE 256 +Accepted TLSv1.1 256 bits ADH-AES256-SHA  DHE 1024 bits +Accepted TLSv1.1 256 bits ADH-CAMELLIA256-SHA  DHE 1024 bits +Accepted TLSv1.1 128 bits ECDHE-RSA-AES128-SHA Curve P-256 DHE 256 +Accepted TLSv1.1 128 bits DHE-RSA-AES128-SHA DHE 1024 bits +Accepted TLSv1.1 128 bits DHE-RSA-SEED-SHA DHE 1024 bits +Accepted TLSv1.1 128 bits DHE-RSA-CAMELLIA128-SHA DHE 1024 bits +Accepted TLSv1.1 128 bits AECDH-AES128-SHA  Curve P-256 DHE 256 +Accepted TLSv1.1 128 bits ADH-AES128-SHA  DHE 1024 bits +Accepted TLSv1.1 128 bits ADH-SEED-SHA  DHE 1024 bits +Accepted TLSv1.1 128 bits ADH-CAMELLIA128-SHA  DHE 1024 bits +Accepted TLSv1.1 128 bits ECDHE-RSA-RC4-SHA  Curve P-256 DHE 256 +Accepted TLSv1.1 128 bits AECDH-RC4-SHA  Curve P-256 DHE 256 +Accepted TLSv1.1 128 bits ADH-RC4-MD5  DHE 1024 bits +Accepted TLSv1.1 112 bits ECDHE-RSA-DES-CBC3-SHA  Curve P-256 DHE 256 +Accepted TLSv1.1 112 bits DHE-RSA-DES-CBC3-SHA  DHE 1024 bits +Accepted TLSv1.1 112 bits AECDH-DES-CBC3-SHA  Curve P-256 DHE 256 +Accepted TLSv1.1 112 bits ADH-DES-CBC3-SHA  DHE 1024 bits +Accepted TLSv1.1 256 bits AES256-SHA +Accepted TLSv1.1 256 bits CAMELLIA256-SHA +Accepted TLSv1.1 128 bits AES128-SHA +Accepted TLSv1.1 128 bits SEED-SHA +Accepted TLSv1.1 128 bits CAMELLIA128-SHA +Accepted TLSv1.1 128 bits IDEA-CBC-SHA +Accepted TLSv1.1 128 bits RC4-SHA  +Accepted TLSv1.1 128 bits RC4-MD5  +Accepted TLSv1.1 112 bits DES-CBC3-SHA  +Accepted TLSv1.1 40 bits TLS_RSA_EXPORT_WITH_RC4_40_MD5 +Accepted TLSv1.1 40 bits TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 +Accepted TLSv1.1 40 bits TLS_RSA_EXPORT_WITH_DES40_CBC_SHA +Accepted TLSv1.1 56 bits TLS_RSA_WITH_DES_CBC_SHA  +Accepted TLSv1.1 56 bits TLS_DHE_RSA_WITH_DES_CBC_SHA  +Accepted TLSv1.1 56 bits TLS_DH_anon_WITH_DES_CBC_SHA  +Preferred TLSv1.0 256 bits ECDHE-RSA-AES256-SHA Curve P-256 DHE 256 +Accepted TLSv1.0 256 bits DHE-RSA-AES256-SHA DHE 1024 bits +Accepted TLSv1.0 256 bits DHE-RSA-CAMELLIA256-SHA DHE 1024 bits +Accepted TLSv1.0 256 bits AECDH-AES256-SHA  Curve P-256 DHE 256 +Accepted TLSv1.0 256 bits ADH-AES256-SHA  DHE 1024 bits +Accepted TLSv1.0 256 bits ADH-CAMELLIA256-SHA  DHE 1024 bits +Accepted TLSv1.0 128 bits ECDHE-RSA-AES128-SHA Curve P-256 DHE 256 +Accepted TLSv1.0 128 bits DHE-RSA-AES128-SHA DHE 1024 bits +Accepted TLSv1.0 128 bits DHE-RSA-SEED-SHA DHE 1024 bits +Accepted TLSv1.0 128 bits DHE-RSA-CAMELLIA128-SHA DHE 1024 bits +Accepted TLSv1.0 128 bits AECDH-AES128-SHA  Curve P-256 DHE 256 +Accepted TLSv1.0 128 bits ADH-AES128-SHA  DHE 1024 bits +Accepted TLSv1.0 128 bits ADH-SEED-SHA  DHE 1024 bits +Accepted TLSv1.0 128 bits ADH-CAMELLIA128-SHA  DHE 1024 bits +Accepted TLSv1.0 128 bits ECDHE-RSA-RC4-SHA  Curve P-256 DHE 256 +Accepted TLSv1.0 128 bits AECDH-RC4-SHA  Curve P-256 DHE 256 +Accepted TLSv1.0 128 bits ADH-RC4-MD5  DHE 1024 bits +Accepted TLSv1.0 112 bits ECDHE-RSA-DES-CBC3-SHA  Curve P-256 DHE 256 +Accepted TLSv1.0 112 bits DHE-RSA-DES-CBC3-SHA  DHE 1024 bits +Accepted TLSv1.0 112 bits AECDH-DES-CBC3-SHA  Curve P-256 DHE 256 +Accepted TLSv1.0 112 bits ADH-DES-CBC3-SHA  DHE 1024 bits +Accepted TLSv1.0 256 bits AES256-SHA +Accepted TLSv1.0 256 bits CAMELLIA256-SHA +Accepted TLSv1.0 128 bits AES128-SHA +Accepted TLSv1.0 128 bits SEED-SHA +Accepted TLSv1.0 128 bits CAMELLIA128-SHA +Accepted TLSv1.0 128 bits IDEA-CBC-SHA +Accepted TLSv1.0 128 bits RC4-SHA  +Accepted TLSv1.0 128 bits RC4-MD5  +Accepted TLSv1.0 112 bits DES-CBC3-SHA  +Accepted TLSv1.0 40 bits TLS_RSA_EXPORT_WITH_RC4_40_MD5 +Accepted TLSv1.0 40 bits TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 +Accepted TLSv1.0 40 bits TLS_RSA_EXPORT_WITH_DES40_CBC_SHA +Accepted TLSv1.0 56 bits TLS_RSA_WITH_DES_CBC_SHA  +Accepted TLSv1.0 56 bits TLS_DHE_RSA_WITH_DES_CBC_SHA  +Accepted TLSv1.0 56 bits TLS_DH_anon_WITH_DES_CBC_SHA  + + SSL Certificate: +Signature Algorithm: sha256WithRSAEncryption +RSA Key Strength: 1024 + +Subject: howfuckedismydatabase.com +Issuer: /C=XX/ST=Nowhere in particular/L=Nowhere +Not valid before: Dec 3 03:56:52 2019 GMT +Not valid after: Dec 3 03:56:52 2029 GMT diff --git a/docker_test/expected_output/test_6.txt b/docker_test/expected_output/test_6.txt new file mode 100644 index 0000000..be710cb --- /dev/null +++ b/docker_test/expected_output/test_6.txt @@ -0,0 +1,39 @@ + +Connected to 127.0.0.1 + +Testing SSL server localhost on port 4443 using SNI name localhost + + TLS Fallback SCSV: +Server supports TLS Fallback SCSV + + TLS renegotiation: +Session renegotiation not supported + + TLS Compression: +Compression disabled + + Heartbleed: +TLS 1.3 not vulnerable to heartbleed +TLS 1.2 not vulnerable to heartbleed +TLS 1.1 not vulnerable to heartbleed +TLS 1.0 not vulnerable to heartbleed + + SSL Protocols: +SSLv2 is not enabled +SSLv3 is not enabled + + Supported Server Cipher(s): +Preferred TLSv1.3 128 bits TLS_AES_128_GCM_SHA256 Curve 25519 DHE 253 +Accepted TLSv1.3 256 bits TLS_AES_256_GCM_SHA384 Curve 25519 DHE 253 +Accepted TLSv1.3 256 bits TLS_CHACHA20_POLY1305_SHA256 Curve 25519 DHE 253 +Accepted TLSv1.3 128 bits TLS_AES_128_CCM_SHA256 Curve 25519 DHE 253 +Accepted TLSv1.3 128 bits TLS_AES_128_CCM_8_SHA256 Curve 25519 DHE 253 + + SSL Certificate: +Signature Algorithm: sha256WithRSAEncryption +RSA Key Strength: 3072 + +Subject: lmgtfy.com +Issuer: /C=XX/ST=Nowhere in particular/L=Nowhere +Not valid before: Dec 3 04:07:43 2019 GMT +Not valid after: Dec 3 04:07:43 2029 GMT diff --git a/docker_test/expected_output/test_7.txt b/docker_test/expected_output/test_7.txt new file mode 100644 index 0000000..d1101e7 --- /dev/null +++ b/docker_test/expected_output/test_7.txt @@ -0,0 +1,55 @@ + +Connected to 127.0.0.1 + +Testing SSL server localhost on port 4443 using SNI name localhost + + TLS Fallback SCSV: +Server does not support TLS Fallback SCSV + + TLS renegotiation: +Secure session renegotiation supported + + TLS Compression: +Compression enabled (CRIME) + + Heartbleed: +TLS 1.3 not vulnerable to heartbleed +TLS 1.2 not vulnerable to heartbleed +TLS 1.1 not vulnerable to heartbleed +TLS 1.0 not vulnerable to heartbleed + + SSL Protocols: +SSLv2 is enabled +SSLv3 is enabled + + Supported Server Cipher(s): +Preferred TLSv1.0 256 bits ECDHE-RSA-AES256-SHA Curve P-256 DHE 256 +Accepted TLSv1.0 256 bits DHE-RSA-AES256-SHA DHE 512 bits +Accepted TLSv1.0 256 bits DHE-RSA-CAMELLIA256-SHA DHE 512 bits +Accepted TLSv1.0 128 bits ECDHE-RSA-AES128-SHA Curve P-256 DHE 256 +Accepted TLSv1.0 128 bits DHE-RSA-AES128-SHA DHE 512 bits +Accepted TLSv1.0 128 bits DHE-RSA-SEED-SHA DHE 512 bits +Accepted TLSv1.0 128 bits DHE-RSA-CAMELLIA128-SHA DHE 512 bits +Accepted TLSv1.0 128 bits ECDHE-RSA-RC4-SHA  Curve P-256 DHE 256 +Accepted TLSv1.0 112 bits ECDHE-RSA-DES-CBC3-SHA  Curve P-256 DHE 256 +Accepted TLSv1.0 112 bits DHE-RSA-DES-CBC3-SHA  DHE 512 bits +Accepted TLSv1.0 256 bits AES256-SHA +Accepted TLSv1.0 256 bits CAMELLIA256-SHA +Accepted TLSv1.0 128 bits AES128-SHA +Accepted TLSv1.0 128 bits SEED-SHA +Accepted TLSv1.0 128 bits CAMELLIA128-SHA +Accepted TLSv1.0 128 bits IDEA-CBC-SHA +Accepted TLSv1.0 128 bits RC4-SHA  +Accepted TLSv1.0 128 bits RC4-MD5  +Accepted TLSv1.0 112 bits DES-CBC3-SHA  +Accepted TLSv1.0 56 bits TLS_RSA_WITH_DES_CBC_SHA  +Accepted TLSv1.0 56 bits TLS_DHE_RSA_WITH_DES_CBC_SHA  + + SSL Certificate: +Signature Algorithm: sha256WithRSAEncryption +RSA Key Strength: 3072 + +Subject: lmgtfy.com +Issuer: /C=XX/ST=Nowhere in particular/L=Nowhere +Not valid before: Dec 3 04:07:43 2019 GMT +Not valid after: Dec 3 04:07:43 2029 GMT diff --git a/docker_test/expected_output/test_8.txt b/docker_test/expected_output/test_8.txt new file mode 100644 index 0000000..712ffda --- /dev/null +++ b/docker_test/expected_output/test_8.txt @@ -0,0 +1,77 @@ + +Connected to 127.0.0.1 + +Testing SSL server localhost on port 4443 using SNI name localhost + + TLS Fallback SCSV: +Server does not support TLS Fallback SCSV + + TLS renegotiation: +Secure session renegotiation supported + + TLS Compression: +Compression enabled (CRIME) + + Heartbleed: +TLS 1.3 not vulnerable to heartbleed +TLS 1.2 not vulnerable to heartbleed +TLS 1.1 not vulnerable to heartbleed +TLS 1.0 not vulnerable to heartbleed + + SSL Protocols: +SSLv2 is enabled +SSLv3 is enabled + + Supported Server Cipher(s): +Preferred TLSv1.0 256 bits ECDHE-RSA-AES256-SHA Curve P-256 DHE 256 +Accepted TLSv1.0 256 bits DHE-RSA-AES256-SHA DHE 512 bits +Accepted TLSv1.0 256 bits DHE-RSA-CAMELLIA256-SHA DHE 512 bits +Accepted TLSv1.0 256 bits AECDH-AES256-SHA  Curve P-256 DHE 256 +Accepted TLSv1.0 256 bits ADH-AES256-SHA  DHE 512 bits +Accepted TLSv1.0 256 bits ADH-CAMELLIA256-SHA  DHE 512 bits +Accepted TLSv1.0 128 bits ECDHE-RSA-AES128-SHA Curve P-256 DHE 256 +Accepted TLSv1.0 128 bits DHE-RSA-AES128-SHA DHE 512 bits +Accepted TLSv1.0 128 bits DHE-RSA-SEED-SHA DHE 512 bits +Accepted TLSv1.0 128 bits DHE-RSA-CAMELLIA128-SHA DHE 512 bits +Accepted TLSv1.0 128 bits AECDH-AES128-SHA  Curve P-256 DHE 256 +Accepted TLSv1.0 128 bits ADH-AES128-SHA  DHE 512 bits +Accepted TLSv1.0 128 bits ADH-SEED-SHA  DHE 512 bits +Accepted TLSv1.0 128 bits ADH-CAMELLIA128-SHA  DHE 512 bits +Accepted TLSv1.0 128 bits ECDHE-RSA-RC4-SHA  Curve P-256 DHE 256 +Accepted TLSv1.0 128 bits AECDH-RC4-SHA  Curve P-256 DHE 256 +Accepted TLSv1.0 128 bits ADH-RC4-MD5  DHE 512 bits +Accepted TLSv1.0 112 bits ECDHE-RSA-DES-CBC3-SHA  Curve P-256 DHE 256 +Accepted TLSv1.0 112 bits DHE-RSA-DES-CBC3-SHA  DHE 512 bits +Accepted TLSv1.0 112 bits AECDH-DES-CBC3-SHA  Curve P-256 DHE 256 +Accepted TLSv1.0 112 bits ADH-DES-CBC3-SHA  DHE 512 bits +Accepted TLSv1.0 256 bits AES256-SHA +Accepted TLSv1.0 256 bits CAMELLIA256-SHA +Accepted TLSv1.0 128 bits AES128-SHA +Accepted TLSv1.0 128 bits SEED-SHA +Accepted TLSv1.0 128 bits CAMELLIA128-SHA +Accepted TLSv1.0 128 bits IDEA-CBC-SHA +Accepted TLSv1.0 128 bits RC4-SHA  +Accepted TLSv1.0 128 bits RC4-MD5  +Accepted TLSv1.0 112 bits DES-CBC3-SHA  +Accepted TLSv1.0 0 bits ECDHE-RSA-NULL-SHA  Curve P-256 DHE 256 +Accepted TLSv1.0 0 bits AECDH-NULL-SHA  Curve P-256 DHE 256 +Accepted TLSv1.0 0 bits NULL-SHA  +Accepted TLSv1.0 0 bits NULL-MD5  +Accepted TLSv1.0 40 bits TLS_RSA_EXPORT_WITH_RC4_40_MD5 +Accepted TLSv1.0 40 bits TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 +Accepted TLSv1.0 40 bits TLS_RSA_EXPORT_WITH_DES40_CBC_SHA +Accepted TLSv1.0 56 bits TLS_RSA_WITH_DES_CBC_SHA  +Accepted TLSv1.0 40 bits TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA +Accepted TLSv1.0 56 bits TLS_DHE_RSA_WITH_DES_CBC_SHA  +Accepted TLSv1.0 40 bits TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 +Accepted TLSv1.0 40 bits TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA +Accepted TLSv1.0 56 bits TLS_DH_anon_WITH_DES_CBC_SHA  + + SSL Certificate: +Signature Algorithm: sha256WithRSAEncryption +RSA Key Strength: 3072 + +Subject: lmgtfy.com +Issuer: /C=XX/ST=Nowhere in particular/L=Nowhere +Not valid before: Dec 3 04:07:43 2019 GMT +Not valid after: Dec 3 04:07:43 2029 GMT diff --git a/docker_test/expected_output/test_9.txt b/docker_test/expected_output/test_9.txt new file mode 100644 index 0000000..b1800f0 --- /dev/null +++ b/docker_test/expected_output/test_9.txt @@ -0,0 +1,20 @@ + +Connected to 127.0.0.1 + +Testing SSL server localhost on port 4443 using SNI name localhost + + SSL Protocols: +SSLv2 is not enabled +SSLv3 is not enabled + + Supported Server Cipher(s): +Preferred 200 OK TLSv1.2 256 bits ECDHE-RSA-CHACHA20-POLY1305  Curve 25519 DHE 253 + + SSL Certificate: +Signature Algorithm: sha256WithRSAEncryption +RSA Key Strength: 3072 + +Subject: lmgtfy.com +Issuer: /C=XX/ST=Nowhere in particular/L=Nowhere +Not valid before: Dec 3 04:07:43 2019 GMT +Not valid after: Dec 3 04:07:43 2029 GMT diff --git a/docker_test/key_1024.pem b/docker_test/key_1024.pem new file mode 100644 index 0000000..8621f9c --- /dev/null +++ b/docker_test/key_1024.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQDmpPrmBNS3gqCgCB9lKvH4ZpX9FvHzw3P4kNbyN45+8yq7gBUp +f9JYFQO0rqm0hSebJSQUDkhrFfO6onZdsMyN32lPlVPFmBILMBPgaxJTVUOa+TWx +gyVuPgaftrMQMr0Wvhbv+3Xht5hqPTEKe/GEwxXJKPSm2F1AgAkkwlQRzQIDAQAB +AoGBAJgeR7xdg05lQTtLICnBYUXLozEBaSK0zlAqdxnZuonQJ2by2wI746dkdMU+ +TX9aMv0ISftQUEMQf2egryCr8rx+yq8bI7LVF8H210x+8BT0H+gmd0iIcFNJNL0l +WSSIAmRVTbSK0IwsvEDwR+Egcnd8wA/9s/s9d2GmbChjisIBAkEA/QY1YLKkG+IT +Ad7GaOKv/UFQNLu7yLDtfjJcJ+dpjCWPv1B/orh6dwFJ4F+7MYruu0BAXhnvw70s +uyPH9W290QJBAOlbZEZtl5n5iL+czI0Ibkyn9VlZ44kgVQHs9Y5hFG0Hv1VH66EP +hU7ZeUUfSmiPqnTcVEKQFZjl09FSoVzTJz0CQQDROzsUlWTjsdUp7MCBp0ME1+et +U7j7QmOBwb83OEOtorn16GlDc+3BTw16P2+ajlrP+VfA+Q2t/VdqATKvH2qhAkBk +zLJ67Zn/y9czFbMR9KNYf3CuwPJVaF7v7wB/GRYuppsSZne04bRuw+frYMHOeshh +pE7NVdnOavBdSfkj1J3tAkEAjQ/+3cGCBiv9lnDdlszKW/Zq4Uu19znfQSbSbI8L +JezLQJbSlVDPG3W3NSNkLizrOg1H6AG2pnnVq2q++Lt5tQ== +-----END RSA PRIVATE KEY----- diff --git a/docker_test/key_2048.pem b/docker_test/key_2048.pem new file mode 100644 index 0000000..f9b36c9 --- /dev/null +++ b/docker_test/key_2048.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAywGmJp/AoA4TCs6zbXuiBOkho35IeVvpsy7RqM3y3KxkEFnk +/LM6U/ayL+j2vo4/15WPM0PaAGRRbvnQEuI1xvhn/0/T4xP+TBe91pTMo/nKrK/y +cvBLBqLPZQK9SJbHk6mwfgpQs5S/+VHlU9jl7+eQWcR+o3NXtv4XFlQyqx1dcokA +JrL4wr2vGPkigUNU2iI6FwRB4f7Wo1rBNzI49uE97IWuh+VBMPYMp+Zn2Om4ptCy +jdvSI7DEYc6jyKlPzH2UOgd0RkcwivaSpxfXJEBOC8PtOxyLg/KPjUTwUh0nHSpe +OIbT3HKnOErEbbiHQmlYbbcOyinv3hIlRj+PyQIDAQABAoIBAGiA09BkQpviQuk4 +WOOOVmxiut9YHeTjbN3Bx0o3osL4t5Y3QIrZlLgucbH6IjMcNT88jXgdgLbc7ZLM +ZNGjw31G2Pp0VKY735e6TQ6OkP4Ek9HrzUpf6q9i1pKwI1Kf0+Nu4h0wIDUh6OVm +xEAyksO6F/QuE+b+dHQOP0JOW7r7uxTMB/tbs1U+idcIRVrPTlO9Ixuaolmd/flz +jmcwwTtwBe+mA53IywCOV6ZxO3lMKzDkSvViRam37fmSh9JJyPEa6KpPTR5ps3w8 +7eG0u9nsEf1wYVA2u575iH4+uM6250bRuw3icZxTU2FPuMOtzJPnxY+A6q13bteW +h0zdzbUCgYEA6ryUy+BSOIFzX4e6dB2gwmn2PUEF1rO9dOG8H0YktOGHnHFDXECy +FYHf6njWEzwztd9ZiE8YQYjAjn829Gr4e45H6rEPAMzSpOJ/ZoLd6PG8d5L6A7AD +RtMS8KzG2fAMwvd0HJ0N4SwuwhFmq6/TLHB9vstwo0myyYqH2qWIOAcCgYEA3WVC +2VnrcuMZngYpXP+gWQDhkIxI7yqUhTB+OZGxHMMjfJ72JHKOI3StnQWSqhxmFtWF +x+XtnihcaWG+G7Po6TmW75oazoitqXjiixJOXGrN3jcmFj97nIh3NlhG2mskP9Ut +5iDE2w2nDRk1eI+13c7j12/bJy7kdi70gr0l5a8CgYEA03V6nYbAysJiyqYco0ml +bj3CYz/WIKnefBJ2Q74Ohxu77IRj6BEn3BQZQMIGJ2HOO4KuxwppkW+99yBGwzwy +CCwOQS+rkk7xWzPnDNPLUHOkEhvHOdcvvHec0k7y+5UyCdidMsGQpU4F+TFvyi4k +EB5uSJhAKfjUJJa095Sy97UCgYEAlOLpPtP6w+s3qg7IuFLsWY5/Ir9EuRowgRVo +fXyd2BLfBYq9SyuCrRNlQeiihiXM/eQgMJtO3gKUiwYBXA30PwvMlltTVbuS1hqG +dzIbYoks4xjBU0rj7RPU38Yj9/T/jrHlSRKWcB3RTry6OdajXoQosxP1FHezikrv +ghCDsN8CgYEA4JuCSuOxmP5/4MTl9oLUDHDbUBGPZICR+2Y0I76kRISQbHT+oidz +/ceQpOP20fBQquVhMrHmKthyN13TvBSn5SaNIa5SVIIGhVZJQPU1/Udfox1gx7iF +TcFx7dbMIh7byuVRy8iIyaVYr9ZtSX+6mYWFUXVrzF9LTGyDVta6YQA= +-----END RSA PRIVATE KEY----- diff --git a/docker_test/key_3072.pem b/docker_test/key_3072.pem new file mode 100644 index 0000000..7e36eb7 --- /dev/null +++ b/docker_test/key_3072.pem @@ -0,0 +1,39 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIG4gIBAAKCAYEAxA1ToQ2HLVYDmKSjPSlCposbUMYA30BlRXMzdJe1OVBg/qwE +rhURlFAvGF9ljgXFnMZ6oTK164sJXscjNXS/AbqWO9rBeMbUxD85/PRo4emmBVio +e5A/A4xbAvPt1snwgjbtZNTsxZoheUox216/NTJ24c3SGEBOlASBHtT6VBJPamx1 +aALlSlS4jqtLAlkxz6M/XUPeRER6DKYXUi37w0XCZRRk1U2ueM2nfkz47a/GxoeA +WmvWPVW1Bu+VbJb9Hsh/2otyhHZAVX9/fsKZwHf9qcSrutLk5M0ix9NUFnq8qZVu +ZLTZa7/rCw6YnmlOv1mAZJ8sNJtt1wyhMGLebkfVHKERCqk37LRpSzloTu95+uPu +/q+391XMKTOmMHqwhvZBpAoOvN7bs4o8N1JF8hPu+MBGsZUs8P+e9WTJU29zvORW +d7Z/8K1zakihJD9FXcC38OGO88h/7JVxYcMyVUZW3zZKxITlJWl8J18OqQpT66K4 +ceLOW1SjRIeHGX9TAgMBAAECggF/D1D7N5nW9bPClCpIln6itmAnwie16bseLk7R +tkoj3lZpPXwy4WbD+NJK25yYUoAg8B6RdgaAL+as1Lq6BXMZeQkas5Jjiwv9k1dd +MGXny751OfWzM/QQ+DX+5jwoWJ9uKr4fzcDUvptMAi3Jt1mvlnha0UlDIKHlgarY +a5A3/llv2uCeS4HuZ+A2iu7W7VgKjC40xRSISM0Qu+w95i2xfY/1n+/38LIg708h +xrw8tlUFMn1jiazjD+eiPOh6xAEHojAGu1actfW+jg8NySpTGWAUPfTxXV9J6r/c +BdCldXP5lQHfWKBIAKUK9MZyrFFQnZZMdPDXyyKsfbO04gVW5BsEK9Br5dnGbFGu +e+Ve4jOCAC9//wLqgLDL2t3CCnnPU1bGFnqLqzwtEKrEP3XeK1CFLYCwOZ2tUH9h +IbQRZKbEMlsXR4XvplmwjNqRb/uHSIVmPJ1DVXbFZy/2j7i59+Kl+JqINHEPvGc1 +tfLOFvOHYRWRONkylj3O+qH6lyECgcEA+CErcMNYkM7Y2uRRB2UhQQ96NDoflQmg +uObO0XTnhMbRFrRRrgEr0POOo4oCqDSVQk/vJjmB1ugo/IKxGphnAOmi1xDpSXqo +UWnUR34nrqL76ZdV1R3FZX0b4iO9X1R/P9sNl4S0+XCDyAMlcaXroPoUIo9mzxbX +vIAk6lMiJijfzLt7RssVCfgCfHZ9srBMG5oaEfTbFImc9fwjNoJdLTDopEQzA1X5 +AjVa8VhIGyE+uoLkPsy9jBNF9asEEdc/AoHBAMpFSKUdTIXuYOOGltr1qFAMofUU ++ztagHg1/UdV3EOhkYZOfpa4clu++x0MNp+bRySxEK6IOpEtSaKHaJlHnvR4+4e7 +xQp/jBoWCrxWtqXHe3ufyglsq/1ID7HIEGfBs9IAVPx9PkY9IOC8cXX3q9uRB7xM +MCtl/H8QMf01f4p3vEgx+XXb2+MKsjOqOVDpAqfqrcUmTiK9ixC7BJWwWSBAvN4e +2jS4UEOoBiczX6qhKo+tUEddfnAJGnxp2cZG7QKBwHwU8klIltCLb+w+grrE+tUz +LTRS4JpCH0p3uXMLF//RAJxu/e2bDlNGiM0FZgDBkuZ/XKNr3J8gp+ZmYLRhBBlz +vIf6H/8rxGI6HvrFfoiZXopYsIaLhbwTzU7P+pJiiePf4jMkHPAkMPJjiGUFyQhO +JqWFuq7SyH2uQ0ee3RPiGtCh7KrhQZsjl/KvunoSKW0gKetS2/+wNXrZZK6MkJXZ +wGzs4enII2bUUa8hK6XNgTX54LP65MrYlIKey8E0NwKBwHBb3kfCJ8D6Mx4QpHoL +Hi0hZ1ISDqDg3B5qt0BKJKn49TKrJcyptvTZ+Pogz7MHeZSbO04IZKhChPXgzCzh +SR46mlbC6mizg2r2NY57iMg8MI7yqzNjB4MR5Y33OY25Xx9Xid4b4Fz6FephI5HJ +O9EjFi32EIf7BjC7GVmzvx529sMP56gdsl7DkUv70gzs8sm+Jjsu1RadPcPUb26L +YGb3LzMf5kyE2ilLC+f4tLq+/jqDpuWNvO+VTv4veoaW3QKBwQDQlmXDJ+4SdYnD +QkHis9G5AnyXkUHhBFTWLyhsJMrt3CZyVp8L7xXgEJTsSVoyvURimeBmua4LEqci +5PPo1fOfyEqUIrHIJVR26ATeMsxC3icV6kna7cD0K1BILtAGTJeO7sWceFhl2QJb +E4wio0Vljyt+foytCL/KV3bIj/OYGk8bUp1OMzEIXot4kx3l2SOf+cYE5UDca9Ey +Z/6IvSvAP/JSqo2pk4azaqxSuZIMQnZB2YlFxllCZ6ce/Z6YcSs= +-----END RSA PRIVATE KEY----- diff --git a/docker_test/key_notes.txt b/docker_test/key_notes.txt new file mode 100644 index 0000000..91c9704 --- /dev/null +++ b/docker_test/key_notes.txt @@ -0,0 +1,8 @@ +There is one Certificate Authority in this directory: ca_cert.pem / ca_key.pem. + +This CA directly signed these certificates (with their corresponding keys): + * cert_1024.crt / key_3072.pem + * cert_2048.crt / key_2048.pem + * cert_3072.crt / key_3072.pem + +The 1024, 2048, and 3072 refer to the RSA key size. diff --git a/docker_test/nginx_site_client_cert_required b/docker_test/nginx_site_client_cert_required new file mode 100644 index 0000000..16e20e2 --- /dev/null +++ b/docker_test/nginx_site_client_cert_required @@ -0,0 +1,21 @@ +server { + listen 443 ssl default_server; + listen [::]:443 ssl default_server; + gzip off; + root /var/www/html; + index index.html index.nginx-debian.html; + server_name _; + location / { + try_files $uri $uri/ =404; + } + # Only TLSv1.2 with one cipher is specified, so the test that runs against this + # finishes quicker (all that's needed is the HTTP response of one successful + # TLS connection). + ssl_protocols TLSv1.2; + ssl_ciphers ECDHE-RSA-CHACHA20-POLY1305; + ssl_prefer_server_ciphers on; + ssl_certificate /etc/ssl/cert_3072.crt; + ssl_certificate_key /etc/ssl/key_3072.pem; + ssl_client_certificate /etc/ssl/ca_cert.pem; + ssl_verify_client on; +} diff --git a/docker_test/nginx_test9.conf b/docker_test/nginx_test9.conf new file mode 100644 index 0000000..aea676c --- /dev/null +++ b/docker_test/nginx_test9.conf @@ -0,0 +1,21 @@ +user www-data; +worker_processes auto; +pid /run/nginx.pid; +daemon off; + +events { + worker_connections 768; +} + +http { + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + include /etc/nginx/mime.types; + default_type application/octet-stream; + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + include /etc/nginx/sites-available/nginx_site_client_cert_required; +} From 9578a405782275c20aadde47f15b8a52f242b6cf Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Fri, 13 Dec 2019 17:13:29 -0500 Subject: [PATCH 35/52] Added key exchange group enumeration. Added 512-bit RSA key test. Added GnuTLS to docker image and key exchange group tests. --- docker_test.sh | 142 ++++- docker_test/Dockerfile | 12 +- docker_test/cert_512.crt | 20 + docker_test/dhparams_512.pem | 4 + docker_test/expected_output/test_12.txt | 55 ++ docker_test/expected_output/test_13.txt | 79 +++ docker_test/expected_output/test_14.txt | 60 +++ docker_test/expected_output/test_4.txt | 7 + docker_test/expected_output/test_6.txt | 7 + docker_test/key_512.pem | 9 + docker_test/key_notes.txt | 13 +- sslscan.c | 658 ++++++++++++++++++------ sslscan.h | 2 + 13 files changed, 902 insertions(+), 166 deletions(-) create mode 100644 docker_test/cert_512.crt create mode 100644 docker_test/dhparams_512.pem create mode 100644 docker_test/expected_output/test_12.txt create mode 100644 docker_test/expected_output/test_13.txt create mode 100644 docker_test/expected_output/test_14.txt create mode 100644 docker_test/key_512.pem diff --git a/docker_test.sh b/docker_test.sh index 4513c3b..2da007c 100755 --- a/docker_test.sh +++ b/docker_test.sh @@ -11,7 +11,7 @@ # # For debugging purposes, here is a cheat sheet for manually running the docker image: # -# docker run -p 4443:443 --security-opt seccomp:unconfined -it sslscan-test:1 /bin/bash +# docker run -p 4443:443 --security-opt seccomp:unconfined -it sslscan-test:2 /bin/bash # # @@ -26,7 +26,7 @@ # This is the docker tag for the image. If this tag doesn't exist, then we assume the # image is out of date, and generate a new one with this tag. -IMAGE_VERSION=1 +IMAGE_VERSION=2 # This is the name of our docker image. IMAGE_NAME=sslscan-test @@ -54,6 +54,12 @@ function check_if_docker_image_exists { } +# Compile all version of GnuTLS. +function compile_gnutls_all { + compile_gnutls '3.6.11.1' +} + + # Compile all versions of OpenSSL. function compile_openssl_all { compile_openssl '1.0.0' @@ -118,6 +124,107 @@ function compile_openssl { } +# Compile a specific version of GnuTLS. +function compile_gnutls { + gnutls_version=$1 + + gnutls_url= + nettle_url= + gnutls_expected_sha256= + nettle_expected_sha256= + gnutls_filename= + nettle_filename= + gnutls_source_dir= + nettle_source_dir= + nettle_version= + compile_num_procs=$NUM_PROCS + compile_nettle=0 + if [[ $gnutls_version == '3.6.11.1' ]]; then + gnutls_url=https://www.gnupg.org/ftp/gcrypt/gnutls/v3.6/gnutls-3.6.11.1.tar.xz + gnutls_expected_sha256=fbba12f3db9a55dbf027e14111755817ec44b57eabec3e8089aac8ac6f533cf8 + gnutls_filename=gnutls-3.6.11.1.tar.xz + gnutls_source_dir=gnutls-3.6.11.1 + nettle_version=3.5.1 + nettle_url=https://ftp.gnu.org/gnu/nettle/nettle-3.5.1.tar.gz + nettle_expected_sha256=75cca1998761b02e16f2db56da52992aef622bf55a3b45ec538bc2eedadc9419 + nettle_filename=nettle-3.5.1.tar.gz + nettle_source_dir=nettle-3.5.1 + compile_nettle=1 + else + echo -e "${REDB}Error: GnuTLS v${gnutls_version} is unknown!${CLR}" + exit 1 + fi + + # Download GnuTLS. + echo -e "\n${YELLOWB}Downloading GnuTLS v${gnutls_version}...${CLR}\n" + wget $gnutls_url + + # Download nettle. + echo -e "\n${YELLOWB}Downloading nettle library v${nettle_version}...${CLR}\n" + wget $nettle_url + + # Check the SHA256 hashes. + gnutls_actual_sha256=`sha256sum ${gnutls_filename} | cut -f1 -d" "` + nettle_actual_sha256=`sha256sum ${nettle_filename} | cut -f1 -d" "` + + if [[ ($gnutls_actual_sha256 != $gnutls_expected_sha256) || ($nettle_actual_sha256 != $nettle_expected_sha256) ]]; then + echo -e "${REDB}GnuTLS/nettle actual hashes differ from expected hashes! ${CLR}\n" + echo -e "\tGnuTLS expected hash: ${gnutls_expected_sha256}\n" + echo -e "\tGnuTLS actual hash: ${gnutls_actual_sha256}\n" + echo -e "\tnettle expected hash: ${nettle_expected_sha256}\n" + echo -e "\tnettle actual hash: ${nettle_actual_sha256}\n\n" + exit 1 + else + echo -e "${GREEN}Hashes verified.${CLR}\n" + fi + + tar xJf $gnutls_filename + + if [[ $compile_nettle == 1 ]]; then + tar xzf $nettle_filename + mv $nettle_source_dir nettle + + # Configure and compile nettle. + echo -e "\n\n${YELLOWB}Compiling nettle v${nettle_version} with \"-j ${compile_num_procs}\"...${CLR}" + pushd nettle + ./configure && make -j $compile_num_procs + + if [[ ! -f libnettle.so || ! -f libhogweed.so ]]; then + echo -e "${REDB}Error: compilation failed! libnettle.so and/or libhogweed.so not found.${CLR}" + exit 1 + fi + popd + fi + + # Configure and compile GnuTLS. + echo -e "\n\n${YELLOWB}Compiling GnuTLS v${gnutls_version} with \"-j ${compile_num_procs}\"...${CLR}" + pushd $gnutls_source_dir + nettle_source_dir_abs=`readlink -m ../nettle` + nettle_parent_dir=`readlink -m ..` + NETTLE_CFLAGS=-I${nettle_parent_dir} NETTLE_LIBS="-L${nettle_source_dir_abs} -lnettle" HOGWEED_CFLAGS=-I${nettle_parent_dir} HOGWEED_LIBS="-L${nettle_source_dir_abs} -lhogweed" ./configure --with-included-libtasn1 --with-included-unistring --without-p11-kit + make CFLAGS=-I${nettle_parent_dir} LDFLAGS="-L${nettle_source_dir_abs} -lhogweed -lnettle" -j $compile_num_procs + + # Ensure that the gnutls-serv and gnutls-cli tools were built + if [[ (! -f "src/.libs/gnutls-cli") || (! -f "src/.libs/gnutls-serv") ]]; then + echo -e "${REDB}Error: compilation failed! gnutls-cli and/or gnutls-serv not found.${CLR}\n" + exit 1 + fi + + # Copy the gnutls-cli and gnutls-serv apps to the top-level docker building dir as, e.g. 'gnutls-cli-v3.6.11.1'. Then we can delete the source code directory and move on. + cp "lib/.libs/libgnutls.so" "../libgnutls.so.30" + cp "src/.libs/gnutls-cli" "../gnutls-cli-v${gnutls_version}" + cp "src/.libs/gnutls-serv" "../gnutls-serv-v${gnutls_version}" + cp "${nettle_source_dir_abs}/libhogweed.so" "../libhogweed.so.5" + cp "${nettle_source_dir_abs}/libnettle.so" "../libnettle.so.7" + popd + + + # Delete the source code directory now that we built the tools and moved them out. + rm -rf ${gnutls_source_dir} + echo -e "\n\n${YELLOWB}Compilation of GnuTLS v${gnutls_version} finished.${CLR}\n\n" +} + + # Creates a new docker image. function create_docker_image { # Create a new temporary directory. @@ -133,6 +240,9 @@ function create_docker_image { # Compile the versions of OpenSSL. compile_openssl_all + # Compile the versions of GnuTLS. + compile_gnutls_all + # Now build the docker image! echo -e "${YELLOWB}Creating docker image...${CLR}" docker build --tag $IMAGE_NAME:$IMAGE_VERSION . @@ -156,6 +266,9 @@ function run_tests { run_test_9 "0" run_test_10 "0" run_test_11 "0" + run_test_12 "0" + run_test_13 "0" + run_test_14 "0" } @@ -225,6 +338,24 @@ function run_test_11 { } +# 512-bit DH, 512-bit RSA key with MD5 signature. +function run_test_12 { + run_test $1 '12' "/openssl_v1.0.0/openssl s_server -accept 443 -dhparam /etc/ssl/dhparams_512.pem -key /etc/ssl/key_512.pem -cert /etc/ssl/cert_512.crt" "" +} + + +# Default GnuTLS. +function run_test_13 { + run_test $1 '13' "/gnutls-3.6.11.1/gnutls-serv -p 443 --x509certfile=/etc/ssl/cert_3072.crt --x509keyfile=/etc/ssl/key_3072.pem" "" +} + + +# GnuTLS with only TLSv1.2 and TLSv1.3, and secp521r1 and ffdhe8192 groups. +function run_test_14 { + run_test $1 '14' "/gnutls-3.6.11.1/gnutls-serv -p 443 --priority=NORMAL:-VERS-TLS1.1:-VERS-TLS1.0:-GROUP-X25519:-GROUP-SECP256R1:-GROUP-SECP384R1:-GROUP-FFDHE2048:-GROUP-FFDHE3072:-GROUP-FFDHE4096:-GROUP-FFDHE6144 --x509certfile=/etc/ssl/cert_3072.crt --x509keyfile=/etc/ssl/key_3072.pem" "" +} + + # Run a test. Set the first argument to '1' to enable test debugging. # Second argument is the test number to run. Third argument is the executable and # its args to be run inside the container.. @@ -326,6 +457,13 @@ if [[ $? != 0 ]]; then exit 1 fi +# Ensure that the libgmp-dev and m4 packages are installed. +dpkg -l libgmp-dev m4 > /dev/null +if [[ $? != 0 ]]; then + echo -e "${REDB}Error: libgmp-dev and/or m4 packages not installed. Fix with: apt install libgmp-dev m4${CLR}" + exit 1 +fi + # Make sure sslscan has been built. if [[ ! -f sslscan ]]; then echo -e "${REDB}Error: sslscan executable not found. Build it first!${CLR}" diff --git a/docker_test/Dockerfile b/docker_test/Dockerfile index 1cbe18a..6e0d0d7 100644 --- a/docker_test/Dockerfile +++ b/docker_test/Dockerfile @@ -1,9 +1,17 @@ FROM ubuntu:18.04 +# Copy OpenSSL's 'openssl' tools. COPY openssl_prog_v1.0.0 /openssl_v1.0.0/openssl COPY openssl_prog_v1.0.2 /openssl_v1.0.2/openssl COPY openssl_prog_v1.1.1 /openssl_v1.1.1/openssl +# Copy GnuTLS client & server tools, along with their required libraries. +COPY gnutls-cli-v3.6.11.1 /gnutls-3.6.11.1/gnutls-cli +COPY gnutls-serv-v3.6.11.1 /gnutls-3.6.11.1/gnutls-serv +COPY libhogweed.so.5 /usr/lib/ +COPY libnettle.so.7 /usr/lib/ +COPY libgnutls.so.30 /usr/lib/x86_64-linux-gnu/ + # Copy certificates, keys, and DH parameters. COPY *.pem /etc/ssl/ COPY *.crt /etc/ssl/ @@ -15,7 +23,9 @@ COPY nginx_test9.conf /etc/nginx/ # Install nginx for some tests. # Install strace for potential debugging, and rsyslog to enable system log gathering. RUN apt update 2> /dev/null -RUN apt install -y nginx strace rsyslog 2> /dev/null +RUN apt install -y nginx strace rsyslog ca-certificates 2> /dev/null RUN apt clean 2> /dev/null +RUN update-ca-certificates + EXPOSE 443 diff --git a/docker_test/cert_512.crt b/docker_test/cert_512.crt new file mode 100644 index 0000000..604aa48 --- /dev/null +++ b/docker_test/cert_512.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDSjCCATICCQC6PCarUG/VGDANBgkqhkiG9w0BAQQFADA/MQswCQYDVQQGEwJY +WDEeMBwGA1UECAwVTm93aGVyZSBpbiBwYXJ0aWN1bGFyMRAwDgYDVQQHDAdOb3do +ZXJlMB4XDTE5MTIxMzAzNTYyMloXDTI5MTIxMzAzNTYyMlowVzELMAkGA1UEBhMC +WFgxHjAcBgNVBAgMFU5vd2hlcmUgaW4gcGFydGljdWxhcjEQMA4GA1UEBwwHTm93 +aGVyZTEWMBQGA1UEAwwNZ2VvY2l0aWVzLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sA +MEgCQQDL3c8fl0i1RqSy1ctDSAWVbOpOy8b4ruQspvuZ9M28LGCrYq2pSL3NBz3p +CYpNaP0C4KnDvN/N+8DkvIT1NJPVAgMBAAEwDQYJKoZIhvcNAQEEBQADggIBADgl +k3V0s2HTPreUrn37fNwj9jYlATJGiQEy8tOoU42j6hK1nhVDq947JCtRXN3ykQkp +bGWcK8TioA+IgPopW8as7rPPzbG330LYUqTub4v3r7b8NqMQBJeRp5EbDj7cvppW +L8Op/pKNJBdFCL+qp4vw+k31ZALcDLfU2evGLD5cq7S/FmzQs7es0c13RICPK3nI +X4AC19isu52zzMXXECPL51nbWbVH7MRQt/UPzfgyDfe+UIAUpR/cvGqree/fWL2D +UQrIOD/k789XzrynRfjlJjxeSWlIyrSYD+zedjxUyn+L6YfcEwUfaqvfYn1YOeKZ +BXNNTxWWZQtdlXif1L/Tk0xHrXlpMNJOmXUnKu9Wb/7ovTfjxiXHnwrhmOHZAn6O +e1Oev5tnMmVWEtp0c1uowX4BTKtl5v/a827cTSJDVm5Va+cfIGL0MkjFcPz4zq04 +Ke/22SM4XdEiUvSiiYj/NrTI4txLid0d+gRZZIzoTnybUobBZUFWYvIFqyi990OF +Mnjercyzb5uEpCiq2xZVwAKSUNMzFqzv+zerN3otOwi3lIY1evNkRdGngmmItEUD +wvNgfpQApqAUH81zFKpnCmOIMZ3XDed+xO7JCJKr1zZ6+qyEhtrew8RL2hMHIok0 +jQQ3dyi39Ekmfr+CyKvPBQ+F4qtMHgv7VFd73RBf +-----END CERTIFICATE----- diff --git a/docker_test/dhparams_512.pem b/docker_test/dhparams_512.pem new file mode 100644 index 0000000..2ded3fb --- /dev/null +++ b/docker_test/dhparams_512.pem @@ -0,0 +1,4 @@ +-----BEGIN DH PARAMETERS----- +MEYCQQDGepU1BSbkViIkFsK+7q68p2ISObhxXRf9uZAqi1jfEhuFrE9IXrhs1CFe +QFW4cLx60bJttVU6acun8aaySWSjAgEC +-----END DH PARAMETERS----- diff --git a/docker_test/expected_output/test_12.txt b/docker_test/expected_output/test_12.txt new file mode 100644 index 0000000..a1f93f7 --- /dev/null +++ b/docker_test/expected_output/test_12.txt @@ -0,0 +1,55 @@ + +Connected to 127.0.0.1 + +Testing SSL server localhost on port 4443 using SNI name localhost + + TLS Fallback SCSV: +Server does not support TLS Fallback SCSV + + TLS renegotiation: +Secure session renegotiation supported + + TLS Compression: +Compression enabled (CRIME) + + Heartbleed: +TLS 1.3 not vulnerable to heartbleed +TLS 1.2 not vulnerable to heartbleed +TLS 1.1 not vulnerable to heartbleed +TLS 1.0 not vulnerable to heartbleed + + SSL Protocols: +SSLv2 is enabled +SSLv3 is enabled + + Supported Server Cipher(s): +Preferred TLSv1.0 256 bits ECDHE-RSA-AES256-SHA Curve P-256 DHE 256 +Accepted TLSv1.0 256 bits DHE-RSA-AES256-SHA DHE 512 bits +Accepted TLSv1.0 256 bits DHE-RSA-CAMELLIA256-SHA DHE 512 bits +Accepted TLSv1.0 128 bits ECDHE-RSA-AES128-SHA Curve P-256 DHE 256 +Accepted TLSv1.0 128 bits DHE-RSA-AES128-SHA DHE 512 bits +Accepted TLSv1.0 128 bits DHE-RSA-SEED-SHA DHE 512 bits +Accepted TLSv1.0 128 bits DHE-RSA-CAMELLIA128-SHA DHE 512 bits +Accepted TLSv1.0 128 bits ECDHE-RSA-RC4-SHA  Curve P-256 DHE 256 +Accepted TLSv1.0 112 bits ECDHE-RSA-DES-CBC3-SHA  Curve P-256 DHE 256 +Accepted TLSv1.0 112 bits DHE-RSA-DES-CBC3-SHA  DHE 512 bits +Accepted TLSv1.0 256 bits AES256-SHA +Accepted TLSv1.0 256 bits CAMELLIA256-SHA +Accepted TLSv1.0 128 bits AES128-SHA +Accepted TLSv1.0 128 bits SEED-SHA +Accepted TLSv1.0 128 bits CAMELLIA128-SHA +Accepted TLSv1.0 128 bits IDEA-CBC-SHA +Accepted TLSv1.0 128 bits RC4-SHA  +Accepted TLSv1.0 128 bits RC4-MD5  +Accepted TLSv1.0 112 bits DES-CBC3-SHA  +Accepted TLSv1.0 56 bits TLS_RSA_WITH_DES_CBC_SHA  +Accepted TLSv1.0 56 bits TLS_DHE_RSA_WITH_DES_CBC_SHA  + + SSL Certificate: +Signature Algorithm: md5WithRSAEncryption +RSA Key Strength: 512 + +Subject: geocities.com +Issuer: /C=XX/ST=Nowhere in particular/L=Nowhere +Not valid before: Dec 13 03:56:22 2019 GMT +Not valid after: Dec 13 03:56:22 2029 GMT diff --git a/docker_test/expected_output/test_13.txt b/docker_test/expected_output/test_13.txt new file mode 100644 index 0000000..047dc1c --- /dev/null +++ b/docker_test/expected_output/test_13.txt @@ -0,0 +1,79 @@ + +Connected to 127.0.0.1 + +Testing SSL server localhost on port 4443 using SNI name localhost + + TLS Fallback SCSV: +Server supports TLS Fallback SCSV + + TLS renegotiation: +Secure session renegotiation supported + + TLS Compression: +Compression disabled + + Heartbleed: +TLS 1.3 not vulnerable to heartbleed +TLS 1.2 not vulnerable to heartbleed +TLS 1.1 not vulnerable to heartbleed +TLS 1.0 not vulnerable to heartbleed + + SSL Protocols: +SSLv2 is not enabled +SSLv3 is not enabled + + Supported Server Cipher(s): +Preferred TLSv1.3 128 bits TLS_AES_128_GCM_SHA256 Curve 25519 DHE 253 +Accepted TLSv1.3 256 bits TLS_AES_256_GCM_SHA384 Curve 25519 DHE 253 +Accepted TLSv1.3 256 bits TLS_CHACHA20_POLY1305_SHA256 Curve 25519 DHE 253 +Accepted TLSv1.3 128 bits TLS_AES_128_CCM_SHA256 Curve 25519 DHE 253 +Preferred TLSv1.2 256 bits ECDHE-RSA-AES256-GCM-SHA384  Curve 25519 DHE 253 +Accepted TLSv1.2 256 bits DHE-RSA-AES256-GCM-SHA384  DHE 2048 bits +Accepted TLSv1.2 256 bits ECDHE-RSA-CHACHA20-POLY1305  Curve 25519 DHE 253 +Accepted TLSv1.2 256 bits DHE-RSA-CHACHA20-POLY1305  DHE 2048 bits +Accepted TLSv1.2 256 bits DHE-RSA-AES256-CCM DHE 2048 bits +Accepted TLSv1.2 128 bits ECDHE-RSA-AES128-GCM-SHA256  Curve 25519 DHE 253 +Accepted TLSv1.2 128 bits DHE-RSA-AES128-GCM-SHA256  DHE 2048 bits +Accepted TLSv1.2 128 bits DHE-RSA-AES128-CCM DHE 2048 bits +Accepted TLSv1.2 256 bits ECDHE-RSA-AES256-SHA Curve 25519 DHE 253 +Accepted TLSv1.2 256 bits DHE-RSA-AES256-SHA DHE 2048 bits +Accepted TLSv1.2 128 bits ECDHE-RSA-AES128-SHA Curve 25519 DHE 253 +Accepted TLSv1.2 128 bits DHE-RSA-AES128-SHA DHE 2048 bits +Accepted TLSv1.2 256 bits AES256-GCM-SHA384 +Accepted TLSv1.2 256 bits AES256-CCM +Accepted TLSv1.2 128 bits AES128-GCM-SHA256 +Accepted TLSv1.2 128 bits AES128-CCM +Accepted TLSv1.2 256 bits AES256-SHA +Accepted TLSv1.2 128 bits AES128-SHA +Preferred TLSv1.1 256 bits ECDHE-RSA-AES256-SHA Curve 25519 DHE 253 +Accepted TLSv1.1 256 bits DHE-RSA-AES256-SHA DHE 2048 bits +Accepted TLSv1.1 128 bits ECDHE-RSA-AES128-SHA Curve 25519 DHE 253 +Accepted TLSv1.1 128 bits DHE-RSA-AES128-SHA DHE 2048 bits +Accepted TLSv1.1 256 bits AES256-SHA +Accepted TLSv1.1 128 bits AES128-SHA +Preferred TLSv1.0 256 bits ECDHE-RSA-AES256-SHA Curve 25519 DHE 253 +Accepted TLSv1.0 256 bits DHE-RSA-AES256-SHA DHE 2048 bits +Accepted TLSv1.0 128 bits ECDHE-RSA-AES128-SHA Curve 25519 DHE 253 +Accepted TLSv1.0 128 bits DHE-RSA-AES128-SHA DHE 2048 bits +Accepted TLSv1.0 256 bits AES256-SHA +Accepted TLSv1.0 128 bits AES128-SHA + + Server Key Exchange Group(s): +X25519 (128 bits) +secp256r1 [P-256] (128 bits) +secp384r1 [P-384] (192 bits) +secp521r1 [P-521] (256 bits) +ffdhe2048 (112 bits) +ffdhe3072 (128 bits) +ffdhe4096 (150 bits) +ffdhe6144 (175 bits) +ffdhe8192 (192 bits) + + SSL Certificate: +Signature Algorithm: sha256WithRSAEncryption +RSA Key Strength: 3072 + +Subject: lmgtfy.com +Issuer: /C=XX/ST=Nowhere in particular/L=Nowhere +Not valid before: Dec 3 04:07:43 2019 GMT +Not valid after: Dec 3 04:07:43 2029 GMT diff --git a/docker_test/expected_output/test_14.txt b/docker_test/expected_output/test_14.txt new file mode 100644 index 0000000..d22696c --- /dev/null +++ b/docker_test/expected_output/test_14.txt @@ -0,0 +1,60 @@ + +Connected to 127.0.0.1 + +Testing SSL server localhost on port 4443 using SNI name localhost + + TLS Fallback SCSV: +Server supports TLS Fallback SCSV + + TLS renegotiation: +Session renegotiation not supported + + TLS Compression: +Compression disabled + + Heartbleed: +TLS 1.3 not vulnerable to heartbleed +TLS 1.2 not vulnerable to heartbleed +TLS 1.1 not vulnerable to heartbleed +TLS 1.0 not vulnerable to heartbleed + + SSL Protocols: +SSLv2 is not enabled +SSLv3 is not enabled + + Supported Server Cipher(s): +Preferred TLSv1.3 128 bits TLS_AES_128_GCM_SHA256 Curve P-521 DHE 521 +Accepted TLSv1.3 256 bits TLS_AES_256_GCM_SHA384 Curve P-521 DHE 521 +Accepted TLSv1.3 256 bits TLS_CHACHA20_POLY1305_SHA256 Curve P-521 DHE 521 +Accepted TLSv1.3 128 bits TLS_AES_128_CCM_SHA256 Curve P-521 DHE 521 +Preferred TLSv1.2 256 bits ECDHE-RSA-AES256-GCM-SHA384  Curve P-521 DHE 521 +Accepted TLSv1.2 256 bits DHE-RSA-AES256-GCM-SHA384  DHE 8192 bits +Accepted TLSv1.2 256 bits ECDHE-RSA-CHACHA20-POLY1305  Curve P-521 DHE 521 +Accepted TLSv1.2 256 bits DHE-RSA-CHACHA20-POLY1305  DHE 8192 bits +Accepted TLSv1.2 256 bits DHE-RSA-AES256-CCM DHE 8192 bits +Accepted TLSv1.2 128 bits ECDHE-RSA-AES128-GCM-SHA256  Curve P-521 DHE 521 +Accepted TLSv1.2 128 bits DHE-RSA-AES128-GCM-SHA256  DHE 8192 bits +Accepted TLSv1.2 128 bits DHE-RSA-AES128-CCM DHE 8192 bits +Accepted TLSv1.2 256 bits ECDHE-RSA-AES256-SHA Curve P-521 DHE 521 +Accepted TLSv1.2 256 bits DHE-RSA-AES256-SHA DHE 8192 bits +Accepted TLSv1.2 128 bits ECDHE-RSA-AES128-SHA Curve P-521 DHE 521 +Accepted TLSv1.2 128 bits DHE-RSA-AES128-SHA DHE 8192 bits +Accepted TLSv1.2 256 bits AES256-GCM-SHA384 +Accepted TLSv1.2 256 bits AES256-CCM +Accepted TLSv1.2 128 bits AES128-GCM-SHA256 +Accepted TLSv1.2 128 bits AES128-CCM +Accepted TLSv1.2 256 bits AES256-SHA +Accepted TLSv1.2 128 bits AES128-SHA + + Server Key Exchange Group(s): +secp521r1 [P-521] (256 bits) +ffdhe8192 (192 bits) + + SSL Certificate: +Signature Algorithm: sha256WithRSAEncryption +RSA Key Strength: 3072 + +Subject: lmgtfy.com +Issuer: /C=XX/ST=Nowhere in particular/L=Nowhere +Not valid before: Dec 3 04:07:43 2019 GMT +Not valid after: Dec 3 04:07:43 2029 GMT diff --git a/docker_test/expected_output/test_4.txt b/docker_test/expected_output/test_4.txt index d6d6c4c..bf765b4 100644 --- a/docker_test/expected_output/test_4.txt +++ b/docker_test/expected_output/test_4.txt @@ -59,6 +59,13 @@ Accepted TLSv1.0 128 bits DHE-RSA-AES128-SHA DHE Accepted TLSv1.0 256 bits AES256-SHA Accepted TLSv1.0 128 bits AES128-SHA + Server Key Exchange Group(s): +X25519 (128 bits) +X448 (224 bits) +secp256r1 [P-256] (128 bits) +secp384r1 [P-384] (192 bits) +secp521r1 [P-521] (256 bits) + SSL Certificate: Signature Algorithm: sha256WithRSAEncryption RSA Key Strength: 3072 diff --git a/docker_test/expected_output/test_6.txt b/docker_test/expected_output/test_6.txt index be710cb..7d50208 100644 --- a/docker_test/expected_output/test_6.txt +++ b/docker_test/expected_output/test_6.txt @@ -29,6 +29,13 @@ Accepted TLSv1.3 256 bits TLS_CHACHA20_POLY1305_SHA256 Curve 2 Accepted TLSv1.3 128 bits TLS_AES_128_CCM_SHA256 Curve 25519 DHE 253 Accepted TLSv1.3 128 bits TLS_AES_128_CCM_8_SHA256 Curve 25519 DHE 253 + Server Key Exchange Group(s): +X25519 (128 bits) +X448 (224 bits) +secp256r1 [P-256] (128 bits) +secp384r1 [P-384] (192 bits) +secp521r1 [P-521] (256 bits) + SSL Certificate: Signature Algorithm: sha256WithRSAEncryption RSA Key Strength: 3072 diff --git a/docker_test/key_512.pem b/docker_test/key_512.pem new file mode 100644 index 0000000..4237078 --- /dev/null +++ b/docker_test/key_512.pem @@ -0,0 +1,9 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIBPQIBAAJBAMvdzx+XSLVGpLLVy0NIBZVs6k7Lxviu5Cym+5n0zbwsYKtiralI +vc0HPekJik1o/QLgqcO83837wOS8hPU0k9UCAwEAAQJBAJP8Vj7TXZchSar7oMod +PNhkMI20RKH+qmlzaU4vsyx1Kqcv2uTkAPMugNZZtRP7bOYU9inbH8LUIrHJIpZP +/H0CIQDliBIQF6c7uaVbjCZ4iki9wnGZ5JA8hFZDoREgJCsHxwIhAONgFmVUzsUw +Z/hjjodDMMX9KgZ0pYHSfbKoNRuJzZ+DAiEAp9ooC2igvUZ3rEkDYScPJuXpGXdS +G09TnkVNNsn8RcUCIQCQ2ERMFwOFgHmrNRi1uCrY5Zag+Cv7ELE8X4U9XsLbqwIh +ALM7UlYJ1ZKAFlK2cnqUCiLoD7Ah9eVfg+rOTUVMOa3v +-----END RSA PRIVATE KEY----- diff --git a/docker_test/key_notes.txt b/docker_test/key_notes.txt index 91c9704..eb8b07e 100644 --- a/docker_test/key_notes.txt +++ b/docker_test/key_notes.txt @@ -1,8 +1,19 @@ There is one Certificate Authority in this directory: ca_cert.pem / ca_key.pem. This CA directly signed these certificates (with their corresponding keys): + * cert_512.crt / key_512.pem * cert_1024.crt / key_3072.pem * cert_2048.crt / key_2048.pem * cert_3072.crt / key_3072.pem -The 1024, 2048, and 3072 refer to the RSA key size. +The 512, 1024, 2048, and 3072 refer to the RSA key size. + +--- + +To generate new keys, and sign them by the CA: + +1.) Generate the key: openssl genrsa -out key.pem 1024 + +2.) Make CSR: openssl req -new -key key.pem -out new.csr + +3.) Sign with CA: openssl x509 -req -days 3653 -in new.csr -CA path/to/ca_cert.pem -CAkey path/to/ca_key.pem -CAcreateserial -out new.crt [-md5|-sha1|-sha256] diff --git a/sslscan.c b/sslscan.c index 32b2076..b25ffe4 100644 --- a/sslscan.c +++ b/sslscan.c @@ -3515,6 +3515,10 @@ int testHost(struct sslCheckOptions *options) } } + // Enumerate key exchange groups. + if (options->groups) + testSupportedGroups(options); + // Print certificate if (status == true && options->showCertificate == true) { @@ -3587,6 +3591,7 @@ int main(int argc, char *argv[]) options.fallback = true; options.compression = true; options.heartbleed = true; + options.groups = true; options.starttls_ftp = false; options.starttls_imap = false; options.starttls_irc = false; @@ -3742,6 +3747,10 @@ int main(int argc, char *argv[]) else if (strcmp("--no-heartbleed", argv[argLoop]) == 0) options.heartbleed = false; + // Should we check for key exchange groups? + else if (strcmp("--no-groups", argv[argLoop]) == 0) + options.groups = false; + // StartTLS... FTP else if (strcmp("--starttls-ftp", argv[argLoop]) == 0) options.starttls_ftp = true; @@ -4032,6 +4041,7 @@ int main(int argc, char *argv[]) printf(" %s--no-renegotiation%s Do not check for TLS renegotiation\n", COL_GREEN, RESET); printf(" %s--no-compression%s Do not check for TLS compression (CRIME)\n", COL_GREEN, RESET); printf(" %s--no-heartbleed%s Do not check for OpenSSL Heartbleed (CVE-2014-0160)\n", COL_GREEN, RESET); + printf(" %s--no-groups%s Do not enumerate key exchange groups\n", COL_GREEN, RESET); printf(" %s--starttls-ftp%s STARTTLS setup for FTP\n", COL_GREEN, RESET); printf(" %s--starttls-imap%s STARTTLS setup for IMAP\n", COL_GREEN, RESET); printf(" %s--starttls-irc%s STARTTLS setup for IRC\n", COL_GREEN, RESET); @@ -4465,29 +4475,46 @@ void buffer_append_uint32_t(unsigned char **buffer, size_t *buf_size, size_t *bu buffer_append_bytes(buffer, buf_size, buf_len, (unsigned char *)&i, sizeof(uint32_t)); } -/* Sets the 'ciphersuite_list' arg to a buffer (which must be free()'ed) of ciphersuites for a given TLS version, and sets the 'ciphersuite_list_len' arg to the number of bytes in 'ciphersuite_list'. */ -void makeMissingCiphersuiteList(unsigned char **ciphersuite_list, size_t *ciphersuite_list_len, unsigned int tls_version) { +/* Sets the 'ciphersuite_list' arg to a buffer (which must be free()'ed) of ciphersuites for a given TLS version, and sets the 'ciphersuite_list_len' arg to the number of bytes in 'ciphersuite_list'. When 'type' is CIPHERSUITES_MISSING, then a list of all ciphersuites missing in OpenSSL is returned. When set to CIPHERSUITES_TLSV1_3_ALL, all TLSv1.3 ciphersuites are returned only. */ +#define CIPHERSUITES_MISSING 0 +#define CIPHERSUITES_TLSV1_3_ALL 1 +void makeCiphersuiteList(unsigned char **ciphersuite_list, size_t *ciphersuite_list_len, unsigned int tls_version, unsigned int type) { size_t ciphersuite_list_size = 1024; - if (tls_version == 0) - tls_version = V1_0; - else if (tls_version == 1) - tls_version = V1_1; - else if (tls_version == 2) - tls_version = V1_2; - *ciphersuite_list_len = 0; + // Make the buffer much smaller if we're just returning the list of 5 TLSv1.3 ciphers. + if (type == CIPHERSUITES_TLSV1_3_ALL) + ciphersuite_list_size = 16; + *ciphersuite_list = calloc(ciphersuite_list_size, sizeof(unsigned char)); if (*ciphersuite_list == NULL) { fprintf(stderr, "Failed to create buffer for ciphersuite list.\n"); exit(-1); } + *ciphersuite_list_len = 0; - for (int i = 0; i < (sizeof(missing_ciphersuites) / sizeof(struct missing_ciphersuite)); i++) { - /* Append only those that OpenSSL does not cover, and those that were not already accepted through a previous run. */ - if ((missing_ciphersuites[i].check_tls_versions & tls_version) && ((missing_ciphersuites[i].accepted_tls_versions & tls_version) == 0)) { - buffer_append_ushort(ciphersuite_list, &ciphersuite_list_size, ciphersuite_list_len, missing_ciphersuites[i].id); + if (type == CIPHERSUITES_MISSING) { + if (tls_version == 0) + tls_version = V1_0; + else if (tls_version == 1) + tls_version = V1_1; + else if (tls_version == 2) + tls_version = V1_2; + + for (int i = 0; i < (sizeof(missing_ciphersuites) / sizeof(struct missing_ciphersuite)); i++) { + /* Append only those that OpenSSL does not cover, and those that were not already accepted through a previous run. */ + if ((missing_ciphersuites[i].check_tls_versions & tls_version) && ((missing_ciphersuites[i].accepted_tls_versions & tls_version) == 0)) { + buffer_append_ushort(ciphersuite_list, &ciphersuite_list_size, ciphersuite_list_len, missing_ciphersuites[i].id); + } } + } else if (type == CIPHERSUITES_TLSV1_3_ALL) { + buffer_append_bytes(ciphersuite_list, &ciphersuite_list_size, ciphersuite_list_len, (unsigned char []) { + 0x13, 0x01, // TLS_AES_128_GCM_SHA256 + 0x13, 0x02, // TLS_AES_256_GCM_SHA384 + 0x13, 0x03, // TLS_CHACHA20_POLY1305_SHA256 + 0x13, 0x04, // TLS_AES_128_CCM_SHA256 + 0x13, 0x05, // TLS_AES_128_CCM_8_SHA256 + }, 10); } } @@ -4520,10 +4547,228 @@ char *resolveCipherID(unsigned short cipher_id, int *cipher_bits) { return "UNKNOWN_CIPHER"; } +/* Sets a length field in a TLS packet at the specified offset. */ +void setTLSLength(unsigned char *buf, unsigned int offset, unsigned int length) { + uint16_t u = htons(length); + memcpy(buf + offset, &u, sizeof(u)); +} + +/* Creates a basic set of TLS extensions, including SNI, ec_point_formats, Session Ticket TLS, and signature_algorithms. */ +unsigned char *makeTLSExtensions(size_t *tls_extensions_size, size_t *tls_extensions_len, struct sslCheckOptions *options) { + unsigned char *tls_extensions = NULL; + + + *tls_extensions_size = 64; + tls_extensions = calloc(*tls_extensions_size, sizeof(unsigned char)); + if (tls_extensions == NULL) { + fprintf(stderr, "Failed to allocate buffers for TLS extensions.\n"); + exit(-1); + } + *tls_extensions_len = 0; + + /* Add the length of the extensions (to be filled in later). */ + buffer_append_ushort(&tls_extensions, tls_extensions_size, tls_extensions_len, 0); + + /* Extension: server name */ + uint16_t sni_length = strlen(options->sniname); + uint16_t sni_list_length = sni_length + 3; + uint16_t extension_length = sni_list_length + 2; + + buffer_append_ushort(&tls_extensions, tls_extensions_size, tls_extensions_len, 0x0000); /* Extension: server_name */ + buffer_append_ushort(&tls_extensions, tls_extensions_size, tls_extensions_len, extension_length); + buffer_append_ushort(&tls_extensions, tls_extensions_size, tls_extensions_len, sni_list_length); + buffer_append_bytes(&tls_extensions, tls_extensions_size, tls_extensions_len, (unsigned char []) { 0x00 /* Server Name Type: host_name */ }, 1); + buffer_append_ushort(&tls_extensions, tls_extensions_size, tls_extensions_len, sni_length); /* The length of the hostname. */ + buffer_append_bytes(&tls_extensions, tls_extensions_size, tls_extensions_len, (unsigned char *)options->sniname, sni_length); /* The hostname itself. */ + + /* Extension: ec_point_formats */ + buffer_append_bytes(&tls_extensions, tls_extensions_size, tls_extensions_len, (unsigned char []) { + 0x00, 0x0b, // Extension: ec_point_formats (11) + 0x00, 0x04, // Extension Length (4) + 0x03, // EC Point Formats Length (3) + 0x00, // Uncompressed + 0x01, // ansiX962_compressed_prime + 0x02, // ansiX962_compressed_char2 + }, 8); + + /* Extension: SessionTicket TLS */ + buffer_append_bytes(&tls_extensions, tls_extensions_size, tls_extensions_len, (unsigned char []) { + 0x00, 0x23, // Extension: SessionTicket TLS (35) + 0x00, 0x00, // Extension Length (0) + }, 4); + + /* Extension: signature_algorithms */ + buffer_append_bytes(&tls_extensions, tls_extensions_size, tls_extensions_len, (unsigned char []) { + 0x00, 0x0d, // Extension: signature_algorithms (13) + 0x00, 0x1e, // Extension Length (30) + 0x00, 0x1c, // Signature Hash Algorithms Length (28) + 0x04, 0x03, // ecdsa_secp256r1_sha256 + 0x05, 0x03, // ecdsa_secp384r1_sha384 + 0x06, 0x03, // ecdsa_secp521r1_sha512 + 0x08, 0x07, // ed25519 + 0x08, 0x08, // ed448 + 0x08, 0x09, // rsa_pss_pss_sha256 + 0x08, 0x0a, // rsa_pss_pss_sha384 + 0x08, 0x0b, // rsa_pss_pss_sha512 + 0x08, 0x04, // rsa_pss_rsae_sha256 + 0x08, 0x05, // rsa_pss_rsae_sha384 + 0x08, 0x06, // rsa_pss_rsae_sha512 + 0x04, 0x01, // rsa_pkcs1_sha256 + 0x05, 0x01, // rsa_pkcs1_sha384 + 0x06, 0x01, // rsa_pkcs1_sha512 + }, 34); + + /* Set the extension length. */ + setTLSLength(tls_extensions, 0, *tls_extensions_len - 2); + return tls_extensions; +} + +/* Adds the TLS supported_versions extension, set to TLSv1.3 only. */ +void tlsExtensionAddTLSv1_3(unsigned char **tls_extensions, size_t *tls_extensions_size, size_t *tls_extensions_len) { + buffer_append_bytes(tls_extensions, tls_extensions_size, tls_extensions_len, (unsigned char []) { + 0x00, 0x2b, // supported_versions (43) + 0x00, 0x03, // Length + 0x02, // Supported Versions Length + 0x03, 0x04, // Supported Version: TLS v1.3 + }, 7); + setTLSLength(*tls_extensions, 0, *tls_extensions_len - 2); +} + +/* From socket s, reads a ServerHello from the network. Returns an unsigned char array on success (which the caller must free()), or NULL on failure. */ +unsigned char *getServerHello(int s, size_t *server_hello_len) { + unsigned char *server_hello = NULL; + unsigned char initial5[8] = {0}; // The initial 5 bytes of the packet. + + + /* Read the first 5 bytes to get the Content Type, Version, and Length fields. */ + int bytes_read = 0, n = 0; + while (bytes_read < 5) { + n = recv(s, initial5 + bytes_read, 5 - bytes_read, 0); + if (n <= 0) { + if ((errno != 0) && (errno != ECONNRESET)) + printf_error("recv() failed while reading Server Hello: %d (%s)\n", errno, strerror(errno)); + goto err; + } + bytes_read += n; + } + *server_hello_len = bytes_read; + + /* Ensure that the Content Type is Handshake (22). */ + if (initial5[0] != 0x16) + goto err; + + /* Get the length of the Server Hello record. */ + unsigned short packet_len = (initial5[3] << 8) | initial5[4]; + + server_hello = calloc(packet_len + sizeof(initial5), sizeof(unsigned char)); + if (server_hello == NULL) { + fprintf(stderr, "Failed to create buffer for Server Hello.\n"); + exit(-1); + } + + /* Copy the initial 5 bytes into the beginning of the buffer. */ + memcpy(server_hello, initial5, *server_hello_len); + + /* Read in the Server Hello record. */ + bytes_read = 0; + while (bytes_read < packet_len) { + n = recv(s, server_hello + *server_hello_len + bytes_read, packet_len - bytes_read, 0); + if (n <= 0) { + if ((errno != 0) && (errno != ECONNRESET)) + printf_error("recv() failed while reading Server Hello: %d (%s)\n", errno, strerror(errno)); + goto err; + } + bytes_read += n; + } + *server_hello_len += bytes_read; + + /* Ensure that the Handshake Type is Server Hello (2). */ + if (server_hello[5] != 0x02) + goto err; + + return server_hello; + + err: + FREE(server_hello); + *server_hello_len = 0; + return NULL; +} + +/* Returns a buffer (which the caller must free()) containing a TLS Client Hello message. The number of bytes is stored in 'client_hello_len'. 'version' is set to 0 for TLSv1.0, 1 for TLSv1.1, 2, for TLSv1.2, and 3 for TLSv1.3. The specified ciphersuite list and TLS extensions will be included. */ +unsigned char *makeClientHello(size_t *client_hello_len, struct sslCheckOptions *options, unsigned int version, unsigned char *ciphersuite_list, size_t ciphersuite_list_len, unsigned char *tls_extensions, size_t tls_extensions_len) { + unsigned char *client_hello = NULL; + size_t client_hello_size = 1024; + unsigned int tls_record_version_low_byte = 1, tls_handshake_version_low_byte = 1; + time_t time_now = time(NULL); + + + /* For TLSv1.0, 1.1, and 1.2, the TLS Record version and Handshake version are the same (and what they should be). For TLSv1.3, the TLS Record claims to be TLSv1.0 and the Handshake claims to be TLSv1.2; this is for compatibility of buggy middleware that most implementations follow. */ + if (version < 3) { + tls_record_version_low_byte += version; + tls_handshake_version_low_byte += version; + } else { + tls_record_version_low_byte = 1; + tls_handshake_version_low_byte = 3; + } + + /* Allocate buffers for the Client Hello and TLS extensions. */ + client_hello = calloc(client_hello_size, sizeof(unsigned char)); + if (client_hello == NULL) { + fprintf(stderr, "Failed to allocate buffer for ClientHello.\n"); + exit(-1); + } + *client_hello_len = 0; + + /* Build the TLSv1 Record with the ClientHello message. */ + buffer_append_bytes(&client_hello, &client_hello_size, client_hello_len, (unsigned char []) { + 0x16, // Content Type: Handshake (22) + 0x03, (unsigned char)tls_record_version_low_byte, // Version: TLS 1.x + 0x00, 0x00, // Length (to be filled in later) + 0x01, // Handshake Type: Client Hello + 0x00, 0x00, 0x00, // Length (to be filled in later) + 0x03, (unsigned char)tls_handshake_version_low_byte, // Version: TLS 1.x + }, 11); + + /* "Random" 32 bytes. */ + uint32_t rand = htonl(time_now); + buffer_append_uint32_t(&client_hello, &client_hello_size, client_hello_len, rand); /* The first 4 bytes is the timestamp. */ + + for (int i = 1; i < 8; i++) { + rand = rand + (time_now ^ (uint32_t)((~(i + 0) << 24) | (~(i + 1) << 16) | (~(i + 2) << 8) | (~(i + 3) << 0))); + buffer_append_uint32_t(&client_hello, &client_hello_size, client_hello_len, rand); + } + + /* Session ID Length: 0 */ + buffer_append_bytes(&client_hello, &client_hello_size, client_hello_len, (unsigned char []) { 0x00 }, 1); + + /* Add the length (in bytes) of the ciphersuites list to the Client Hello. */ + buffer_append_ushort(&client_hello, &client_hello_size, client_hello_len, ciphersuite_list_len); + + /* Add the ciphersuite list. */ + buffer_append_bytes(&client_hello, &client_hello_size, client_hello_len, ciphersuite_list, ciphersuite_list_len); + + /* Add the compression options. */ + buffer_append_bytes(&client_hello, &client_hello_size, client_hello_len, (unsigned char []) { + 0x01, // Compression Methods Length (1) + 0x00 // Compression Method: null (0) + }, 2); + + /* Add the extensions to the Client Hello. */ + buffer_append_bytes(&client_hello, &client_hello_size, client_hello_len, tls_extensions, tls_extensions_len); + + /* Set the length of the Client Hello. */ + client_hello[6] = 0; + setTLSLength(client_hello, 7, *client_hello_len - 9); + + /* Set the length of the Record Layer. */ + setTLSLength(client_hello, 3, *client_hello_len - 5); + return client_hello; +} + /* Checks all ciphersuites that OpenSSL does not support. When version is 0, TLSv1.0 is tested. When set to 1, TLSv1.1 is tested. When set to 2, TLSv1.2 is tested. */ int testMissingCiphers(struct sslCheckOptions *options, unsigned int version) { int ret = false, s = 0; - unsigned char *ciphersuite_list = NULL, *client_hello = NULL, *tls_extensions = NULL; + unsigned char *ciphersuite_list = NULL, *client_hello = NULL, *server_hello = NULL, *tls_extensions = NULL; unsigned int tls_version_low_byte = 1; char *tls_printable_name = "TLSv1.0"; @@ -4535,93 +4780,18 @@ int testMissingCiphers(struct sslCheckOptions *options, unsigned int version) { else if (version == 2) tls_printable_name = "TLSv1.2"; + /* Continue until a Server Hello isn't received. */ while (1) { - unsigned short extension_length = 0, sni_list_length = 0, sni_length = 0; - unsigned long time_now = time(NULL); - unsigned char server_hello[128] = {0}; - size_t client_hello_size = 1024, client_hello_len = 0, ciphersuite_list_len = 0; - size_t tls_extensions_size = 256, tls_extensions_len = 0; - struct timeval tval_start = {0}, tval_end = {0}, tval_elapsed = {0}; int cipher_bits = -1; + size_t client_hello_len = 0, ciphersuite_list_len = 0, tls_extensions_size = 256, tls_extensions_len = 0; + unsigned char *client_hello = NULL, *tls_extensions = NULL; char *cipher_name = NULL; + struct timeval tval_start = {0}, tval_end = {0}, tval_elapsed = {0}; gettimeofday(&tval_start, NULL); - /* Allocate buffers for the Client Hello and TLS extensions. */ - client_hello = calloc(client_hello_size, sizeof(unsigned char)); - tls_extensions = calloc(tls_extensions_size, sizeof(unsigned char)); - if ((client_hello == NULL) || (tls_extensions == NULL)) { - fprintf(stderr, "Failed to allocate buffers for ClientHello.\n"); - exit(-1); - } - - /* Build the TLSv1 Record with the ClientHello message. */ - buffer_append_bytes(&client_hello, &client_hello_size, &client_hello_len, (unsigned char []) { - 0x16, // Content Type: Handshake (22) - 0x03, (unsigned char)tls_version_low_byte, // Version: TLS 1.x - 0x00, 0x00, // Length (to be filled in later) - 0x01, // Handshake Type: Client Hello - 0x00, 0x00, 0x00, // Length (to be filled in later) - 0x03, (unsigned char)tls_version_low_byte, // Version: TLS 1.x - }, 11); - - /* "Random" 32 bytes. */ - uint32_t rand = htonl(time_now); - buffer_append_uint32_t(&client_hello, &client_hello_size, &client_hello_len, rand); /* The first 4 bytes is the timestamp. */ - - for (int i = 1; i < 8; i++) { - rand = rand + (time_now ^ (uint32_t)((~(i + 0) << 24) | (~(i + 1) << 16) | (~(i + 2) << 8) | (~(i + 3) << 0))); - buffer_append_uint32_t(&client_hello, &client_hello_size, &client_hello_len, rand); - } - - /* Session ID Length: 0 */ - buffer_append_bytes(&client_hello, &client_hello_size, &client_hello_len, - (unsigned char []) { 0x00 }, 1); - - /* Construct the list of ciphersuites. */ - makeMissingCiphersuiteList(&ciphersuite_list, &ciphersuite_list_len, version); - - /* Add the length (in bytes) of the ciphersuites list to the Client Hello. */ - buffer_append_ushort(&client_hello, &client_hello_size, &client_hello_len, ciphersuite_list_len); - - /* Append the list of ciphersuites to the Client Hello. */ - buffer_append_bytes(&client_hello, &client_hello_size, &client_hello_len, ciphersuite_list, ciphersuite_list_len); - - /* Free the ciphersuite list since we are done with it. */ - FREE(ciphersuite_list); - ciphersuite_list_len = 0; - - /* Add the compression options. */ - buffer_append_bytes(&client_hello, &client_hello_size, &client_hello_len, (unsigned char []) { - 0x01, // Compression Methods Length (1) - 0x00 // Compression Method: null (0) - }, 2); - - /* Add the length of the extensions (to be filled in later). */ - buffer_append_ushort(&tls_extensions, &tls_extensions_size, &tls_extensions_len, 0); - - /* Extension: server name */ - sni_length = strlen(options->sniname); - sni_list_length = sni_length + 3; - extension_length = sni_list_length + 2; - - buffer_append_ushort(&tls_extensions, &tls_extensions_size, &tls_extensions_len, 0x0000); /* Extension: server_name */ - buffer_append_ushort(&tls_extensions, &tls_extensions_size, &tls_extensions_len, extension_length); - buffer_append_ushort(&tls_extensions, &tls_extensions_size, &tls_extensions_len, sni_list_length); - buffer_append_bytes(&tls_extensions, &tls_extensions_size, &tls_extensions_len, (unsigned char []) { 0x00 /* Server Name Type: host_name */ }, 1); - buffer_append_ushort(&tls_extensions, &tls_extensions_size, &tls_extensions_len, sni_length); /* The length of the hostname. */ - buffer_append_bytes(&tls_extensions, &tls_extensions_size, &tls_extensions_len, (unsigned char *)options->sniname, sni_length); /* The hostname itself. */ - - /* Extension: ec_point_formats */ - buffer_append_bytes(&tls_extensions, &tls_extensions_size, &tls_extensions_len, (unsigned char []) { - 0x00, 0x0b, // Extension: ec_point_formats (11) - 0x00, 0x04, // Extension Length (4) - 0x03, // EC Point Formats Length (3) - 0x00, // Uncompressed - 0x01, // ansiX962_compressed_prime - 0x02, // ansiX962_compressed_char2 - }, 8); + tls_extensions = makeTLSExtensions(&tls_extensions_size, &tls_extensions_len, options); /* Extension: supported_groups */ buffer_append_bytes(&tls_extensions, &tls_extensions_size, &tls_extensions_len, (unsigned char []) { @@ -4643,32 +4813,19 @@ int testMissingCiphers(struct sslCheckOptions *options, unsigned int version) { 0x00, 0x0a, // sect283r1 }, 32); - /* Extension: SessionTicket TLS */ - buffer_append_bytes(&tls_extensions, &tls_extensions_size, &tls_extensions_len, (unsigned char []) { - 0x00, 0x23, // Extension: SessionTicket TLS (35) - 0x00, 0x00, // Extension Length (0) - }, 4); + setTLSLength(tls_extensions, 0, tls_extensions_len - 2); - /* Set the extension length. */ - unsigned short us = htons(tls_extensions_len - 2); - memcpy(tls_extensions, &us, sizeof(us)); + /* Construct the list of all ciphersuites not implemented by OpenSSL. */ + makeCiphersuiteList(&ciphersuite_list, &ciphersuite_list_len, version, CIPHERSUITES_MISSING); - /* Add the extensions to the Client Hello. */ - buffer_append_bytes(&client_hello, &client_hello_size, &client_hello_len, tls_extensions, tls_extensions_len); + client_hello = makeClientHello(&client_hello_len, options, version, ciphersuite_list, ciphersuite_list_len, tls_extensions, tls_extensions_len); + + FREE(ciphersuite_list); + ciphersuite_list_len = 0; - /* Free the extensions since we are done with them. */ FREE(tls_extensions); - tls_extensions_len = 0; tls_extensions_size = 0; - - /* Set the length of the Client Hello. */ - client_hello[6] = 0; - us = htons(client_hello_len - 9); - memcpy(client_hello + 7, &us, sizeof(us)); - - /* Set the length of the Record Layer. */ - us = htons(client_hello_len - 5); - memcpy(client_hello + 3, &us, sizeof(us)); + tls_extensions_len = 0; /* Now connect to the target server. */ s = tcpConnect(options); @@ -4681,62 +4838,25 @@ int testMissingCiphers(struct sslCheckOptions *options, unsigned int version) { goto done; /* Returns false. */ } FREE(client_hello); - client_hello_size = 0; client_hello_len = 0; - /* Read the first 5 bytes to get the Content Type, Version, and Length fields. */ - int bytes_read = 0, n = 0; - while (bytes_read < 5) { - n = recv(s, server_hello + bytes_read, 5 - bytes_read, 0); - if (n <= 0) { - if ((errno != 0) && (errno != ECONNRESET)) - printf_error("recv() failed while reading Server Hello: %d (%s)\n", errno, strerror(errno)); - goto done; /* Returns false. */ - } - bytes_read += n; - } - size_t server_hello_len = bytes_read; + size_t server_hello_len = 0; + server_hello = getServerHello(s, &server_hello_len); - /* Check that the TLS version returned is what we sent earlier. */ - if ((server_hello[1] != 0x03) || (server_hello[2] != (unsigned char)tls_version_low_byte)) - goto done; - - /* At this point, the test is considered a success, even if the server rejects our Client Hello. */ - ret = true; - - /* Ensure that the Content Type is Handshake (22). */ - if (server_hello[0] != 0x16) + /* If we don't receive a proper Server Hello message, or its too short, abort. We need to reach at least the session ID field (offset 44). */ + if ((server_hello == NULL) || (server_hello_len < 44)) goto done; - /* Get the length of the Server Hello record. */ - unsigned short packet_len = (server_hello[3] << 8) | server_hello[4]; - - /* Ensure that our buffer can hold the entire record. */ - if (packet_len > sizeof(server_hello)) { - fprintf(stderr, "Error: size of server_hello (%"SIZE_T_FMT") is not large enough for Server Hello (%u).\n", sizeof(server_hello), packet_len); - exit(-1); - } - - /* Read in the Server Hello record. */ - bytes_read = 0; - while (bytes_read < packet_len) { - n = recv(s, server_hello + server_hello_len + bytes_read, packet_len - bytes_read, 0); - if (n <= 0) { - if ((errno != 0) && (errno != ECONNRESET)) - printf_error("recv() failed while reading Server Hello: %d (%s)\n", errno, strerror(errno)); - goto done; - } - bytes_read += n; - } - server_hello_len += bytes_read; - /* Close the socket, since we're done reading. */ CLOSE(s); - /* Ensure that the Handshake Type is Server Hello (2). */ - if (server_hello[5] != 0x02) + /* Check that the TLS version returned is what we sent earlier. */ + if ((server_hello[1] != 0x03) || (server_hello[2] != (unsigned char)tls_version_low_byte)) goto done; + /* At this point, the test is considered a success, even if the server rejects our Client Hello. */ + ret = true; + /* Get the length of the session ID. We must jump over this to reach the ciphersuite selected by the server. */ unsigned int session_id_len = server_hello[43]; @@ -4747,7 +4867,7 @@ int testMissingCiphers(struct sslCheckOptions *options, unsigned int version) { } /* Check that the session ID length wouldn't put us past our buffer boundary. */ - if ((session_id_len + 43 + 2 + 1) > sizeof(server_hello)) { + if ((session_id_len + 43 + 2 + 1) > server_hello_len) { fprintf(stderr, "Error: size of server_hello (%"SIZE_T_FMT") is not large enough to reach cipher suite (%u).\n", sizeof(server_hello), session_id_len + 43 + 2); exit(-1); } @@ -4755,6 +4875,9 @@ int testMissingCiphers(struct sslCheckOptions *options, unsigned int version) { /* Extract the cipher ID. */ unsigned short cipher_id = (server_hello[session_id_len + 43 + 1] << 8) | server_hello[session_id_len + 43 + 2]; + FREE(server_hello); + server_hello_len = 0; + /* Mark this cipher ID as supported by the server, so when we loop again, the next ciphersuite list doesn't include it. */ markFoundCiphersuite(cipher_id, version); @@ -4775,6 +4898,217 @@ int testMissingCiphers(struct sslCheckOptions *options, unsigned int version) { FREE(ciphersuite_list); FREE(tls_extensions); FREE(client_hello); + FREE(server_hello); + return ret; +} + +/* Enumerates all the group key exchanges for TLSv1.3. This could potentially be adapted to support TLSv1.0 - v1.2. */ +int testSupportedGroups(struct sslCheckOptions *options) { + int ret = true; + + struct group_key_exchange { + uint16_t group_id; + char *group_name; + unsigned int group_bit_strength; /* The bit strength equivalent of this group. */ + char *color; + int nid; /* NID for group, or -1 for X25519/X448. */ + unsigned int nid_type; /* One of the NID_TYPE_* flags. */ + uint16_t key_exchange_len; + }; + + /* Bit strength of DHE 2048 and 3072-bit moduli is taken directly from NIST SP 800-57 pt.1, rev4., pg. 53; DHE 4096, 6144, and 8192 are estimated using that document. */ +#define COL_PLAIN "" +#define NID_TYPE_NA 0 /* Not Applicable (i.e.: X25519/X448) */ +#define NID_TYPE_ECDHE 1 /* For P-256/384-521. */ +#define NID_TYPE_DHE 2 /* For ffdhe* */ + struct group_key_exchange group_key_exchanges[] = { + {0x001d, "X25519", 128, COL_GREEN, -1, NID_TYPE_NA, 32}, + {0x001e, "X448", 224, COL_GREEN, -1, NID_TYPE_NA, 56}, + + {0x0017, "secp256r1 [P-256]", 128, COL_PLAIN, NID_X9_62_prime256v1, NID_TYPE_ECDHE, 0}, + {0x0018, "secp384r1 [P-384]", 192, COL_PLAIN, NID_secp384r1, NID_TYPE_ECDHE, 0}, + {0x0019, "secp521r1 [P-521]", 256, COL_PLAIN, NID_secp521r1, NID_TYPE_ECDHE, 0}, + + {0x0100, "ffdhe2048", 112, COL_PLAIN, NID_ffdhe2048, NID_TYPE_DHE, 256}, + {0x0101, "ffdhe3072", 128, COL_PLAIN, NID_ffdhe3072, NID_TYPE_DHE, 384}, + {0x0102, "ffdhe4096", 150, COL_PLAIN, NID_ffdhe4096, NID_TYPE_DHE, 512}, + {0x0103, "ffdhe6144", 175, COL_PLAIN, NID_ffdhe6144, NID_TYPE_DHE, 768}, + {0x0104, "ffdhe8192", 192, COL_PLAIN, NID_ffdhe8192, NID_TYPE_DHE, 1024}, + }; + + unsigned int printed_header = 0; + int s = 0; + unsigned char *client_hello = NULL, *ciphersuite_list = NULL, *tls_extensions = NULL, *server_hello = NULL, *key_exchange = NULL; + size_t client_hello_len = 0, tls_extensions_size = 0, tls_extensions_len = 0, ciphersuite_list_len = 0, server_hello_len = 0, key_exchange_len = 0; + + + /* Get all TLSv1.3 ciphersuites. */ + makeCiphersuiteList(&ciphersuite_list, &ciphersuite_list_len, 3, CIPHERSUITES_TLSV1_3_ALL); + + /* For each key exchange group... */ + for (int i = 0; i < (sizeof(group_key_exchanges) / sizeof(struct group_key_exchange)); i++) { + uint16_t group_id = group_key_exchanges[i].group_id; + char *group_name = group_key_exchanges[i].group_name; + char *color = group_key_exchanges[i].color; + unsigned int group_bit_strength = group_key_exchanges[i].group_bit_strength; + int nid = group_key_exchanges[i].nid; + unsigned nid_type = group_key_exchanges[i].nid_type; + key_exchange_len = group_key_exchanges[i].key_exchange_len; + + /* This will hold the key exchange data that we send to the server. */ + key_exchange = calloc(key_exchange_len, sizeof(unsigned char)); + if (key_exchange == NULL) { + fprintf(stderr, "Failed to create buffer for key exchange.\n"); + exit(-1); + } + + /* Generate the right type of key exchange data. */ + if (nid_type == NID_TYPE_NA) { + + /* Generate "random" data. X25519 and X448 public keys have no discernible structure. */ + srand(time(NULL) ^ 0xdeadbeef); + for (int j = 0; j < key_exchange_len; j++) + key_exchange[j] = rand(); + + } else if (nid_type == NID_TYPE_ECDHE) { + /* Free the buffer, since we will dynamically get the size we need and create a new one. */ + FREE(key_exchange); key_exchange_len = 0; + + /* Generate the ECDHE key. */ + EC_KEY *key = EC_KEY_new_by_curve_name(nid); + if ((key == NULL) || (EC_KEY_generate_key(key) != 1)) { + EC_KEY_free(key); key = NULL; + fprintf(stderr, "Failed to generate ECDHE key for nid %d\n", nid); + continue; + } + + /* Allocate a *new* byte array and put the key into it. */ + unsigned char *kex_buf = NULL; + key_exchange_len = EC_KEY_key2buf(key, POINT_CONVERSION_UNCOMPRESSED, &kex_buf, NULL); + if (kex_buf == NULL) { + EC_KEY_free(key); key = NULL; + fprintf(stderr, "Failed to obtain ECDHE public key bytes.\n"); + continue; + } + + /* The byte array created above needs to be freed with OPENSSL_free(), not free(). To simplify the code, we will copy the bytes to our own array and call OPENSSL_free() immediately. */ + key_exchange = calloc(key_exchange_len, sizeof(unsigned char)); + if (key_exchange == NULL) { + fprintf(stderr, "Failed to create buffer for key exchange.\n"); + exit(-1); + } + memcpy(key_exchange, kex_buf, key_exchange_len); + OPENSSL_free(kex_buf); kex_buf = NULL; + EC_KEY_free(key); key = NULL; + + } else if (nid_type == NID_TYPE_DHE) { + + /* The value (Y) for FFDHE group must be 1 < Y < p - 1 (see RFC7919). Furthermore, GnuTLS checks that Y ^ q mod p == 1 (see GnuTLS v3.6.11.1, lib/nettle/pk.c:291). The easiest way to do this seems to be to actually generate real DH public keys. */ + DH *dh = DH_new_by_nid(nid); + if (!DH_generate_key(dh)) { + FREE(key_exchange); + fprintf(stderr, "Failed to generate DH key for nid %d\n", nid); + continue; + } + + /* Export the public key to our byte array. */ + const BIGNUM *pub_key = NULL; + DH_get0_key(dh, &pub_key, NULL); + if (!BN_bn2binpad(pub_key, key_exchange, key_exchange_len)) { + FREE(key_exchange); + fprintf(stderr, "Failed to get DH key for nid %d\n", nid); + continue; + } + + } else { + /* Use the provided value, since it must be a specific format. */ + //memcpy(key_exchange, group_key_exchanges[i].key_exchange, key_exchange_len); + fprintf(stderr, "Error: unknown NID_TYPE in struct: %d\n", nid_type); + exit(-1); + } + + /* Make generic TLS extensions (with SNI, accepted EC point formats, etc). */ + tls_extensions = makeTLSExtensions(&tls_extensions_size, &tls_extensions_len, options); + + /* Add the supported_versions extension to signify we are using TLS v1.3. */ + tlsExtensionAddTLSv1_3(&tls_extensions, &tls_extensions_size, &tls_extensions_len); + + /* Add the supported_groups extension. Only add the one group we are testing for. */ + buffer_append_bytes(&tls_extensions, &tls_extensions_size, &tls_extensions_len, (unsigned char []) { + 0x00, 0x0a, // Extension Type: supported_groups (10) + 0x00, 0x04, // Extension Length (4) + 0x00, 0x02, // Supported Groups List Length (2) + }, 6); + buffer_append_ushort(&tls_extensions, &tls_extensions_size, &tls_extensions_len, group_id); + + /* Add the key_share extension for the current group type. */ + buffer_append_bytes(&tls_extensions, &tls_extensions_size, &tls_extensions_len, (unsigned char []) { 0x00, 0x33 }, 2); // Extension Type: key_share (51) + buffer_append_ushort(&tls_extensions, &tls_extensions_size, &tls_extensions_len, key_exchange_len + 6); // Extension Length + buffer_append_ushort(&tls_extensions, &tls_extensions_size, &tls_extensions_len, key_exchange_len + 4); // Client Key Share Length + buffer_append_ushort(&tls_extensions, &tls_extensions_size, &tls_extensions_len, group_id); // Group ID. + buffer_append_ushort(&tls_extensions, &tls_extensions_size, &tls_extensions_len, key_exchange_len); // Key Exchange Length + buffer_append_bytes(&tls_extensions, &tls_extensions_size, &tls_extensions_len, key_exchange, key_exchange_len); // Key Exchange + + FREE(key_exchange); + key_exchange_len = 0; + + /* Update the TLS extensions length since we manually added to it. */ + setTLSLength(tls_extensions, 0, tls_extensions_len - 2); + + client_hello = makeClientHello(&client_hello_len, options, 3, ciphersuite_list, ciphersuite_list_len, tls_extensions, tls_extensions_len); + + FREE(tls_extensions); + tls_extensions_size = 0; + tls_extensions_len = 0; + + /* Now connect to the target server. */ + s = tcpConnect(options); + if (s == 0) { + ret = false; + goto done; + } + + /* Send the Client Hello message. */ + if (send(s, client_hello, client_hello_len, 0) <= 0) { + printf_error("send() failed while sending Client Hello: %d (%s)\n", errno, strerror(errno)); + ret = false; + goto done; + } + FREE(client_hello); + client_hello_len = 0; + + server_hello = getServerHello(s, &server_hello_len); + CLOSE(s); + + /* This group is not supported. */ + if (server_hello == NULL) + continue; + + FREE(server_hello); + server_hello_len = 0; + + if (!printed_header) { + printf("\n %sServer Key Exchange Group(s):%s\n", COL_BLUE, RESET); + printed_header = 1; + } + printf("%s%s%s (%d bits)\n", color, group_name, RESET, group_bit_strength); + printf_xml(" \n", group_bit_strength, group_name); + } + + done: + CLOSE(s); + FREE(ciphersuite_list); + ciphersuite_list_len = 0; + + FREE(tls_extensions); + tls_extensions_size = 0; + tls_extensions_len = 0; + + FREE(client_hello); + client_hello_len = 0; + + FREE(server_hello); + server_hello_len = 0; return ret; } diff --git a/sslscan.h b/sslscan.h index 640f9fd..2a7087f 100644 --- a/sslscan.h +++ b/sslscan.h @@ -150,6 +150,7 @@ struct sslCheckOptions int fallback; int compression; int heartbleed; + int groups; int starttls_ftp; int starttls_imap; int starttls_irc; @@ -305,6 +306,7 @@ int testRenegotiation(struct sslCheckOptions *, const SSL_METHOD *); int testfallback(struct sslCheckOptions *, const SSL_METHOD *); #endif int testHeartbleed(struct sslCheckOptions *, const SSL_METHOD *); +int testSupportedGroups(struct sslCheckOptions *options); int testCipher(struct sslCheckOptions *, const SSL_METHOD *); int testMissingCiphers(struct sslCheckOptions *options, unsigned int version); int testProtocolCiphers(struct sslCheckOptions *, const SSL_METHOD *); From 0117ac205259a3bc943249bd50144ee61c6a84c2 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Sat, 14 Dec 2019 22:06:58 -0500 Subject: [PATCH 36/52] Added byte string functions to greatly improve code readability & safety. --- sslscan.c | 526 +++++++++++++++++++++++++++++++----------------------- sslscan.h | 24 ++- 2 files changed, 322 insertions(+), 228 deletions(-) diff --git a/sslscan.c b/sslscan.c index b25ffe4..5627f58 100644 --- a/sslscan.c +++ b/sslscan.c @@ -4419,79 +4419,220 @@ void findMissingCiphers() { } } -/* Appends an array of bytes (in 'bytes') of length 'bytes_len' to an array (in 'buffer'). The current size of 'buffer' is given in 'buf_size'. The current number of bytes used in the buffer is given in 'buf_len'. If the caller tries to append bytes that the current buffer cannot hold, the buffer will be automatically re-sized and the bytes are safely appended. The extended buffer region is zeroed. */ +/* Creates a new byte string of size BS_DEFAULT_NEW_SIZE. Caller must eventually free it with bs_free(). The caller MUST initialize the pointer to NULL, otherwise the heap will be corrupted. */ +void bs_new(bs **b) { + bs_new_size(b, BS_DEFAULT_NEW_SIZE); +} + +/* Creates a new byte string with the specified initial size (or BS_DEFAULT_NEW_SIZE if 0). Caller must eventually free it with bs_free(). The caller MUST initialize the pointer to NULL, otherwise the heap will be corrupted. */ +void bs_new_size(bs **b, size_t new_size) { + if (b == NULL) { + fprintf(stderr, "Error: bs_new*() given NULL pointer!\n"); + exit(-1); + } + + /* If this byte string was already initialized, silently free it, then continue on. */ + if (*b != NULL) + bs_free(b); + + if (new_size == 0) + new_size = BS_DEFAULT_NEW_SIZE; + + *b = calloc(1, sizeof(bs)); + if (*b == NULL) { + fprintf(stderr, "bs_new_size(): failed to allocate new buffer.\n"); + exit(-1); + } + + (*b)->buf = calloc(new_size, sizeof(unsigned char)); + if ((*b)->buf == NULL) { + fprintf(stderr, "bs_new_size(): failed to allocate new buffer.\n"); + exit(-1); + } + + (*b)->size = new_size; + (*b)->len = 0; +} + +/* De-allocates a byte string. May be safely called multiple times. Furthermore, bs_free(NULL) does nothing. */ +void bs_free(bs **b) { + if ((b == NULL) || (*b == NULL)) + return; + + free((*b)->buf); + (*b)->buf = NULL; + + (*b)->size = 0; + (*b)->len = 0; + free(*b); + *b = NULL; +} + +/* Appends an array of bytes to this byte string. The byte string is automatically re-sized if necessary. */ #define OVERFLOW_MESSAGE "Cannot lengthen buffer without overflowing length!\n" -void buffer_append_bytes(unsigned char **buffer, size_t *buf_size, size_t *buf_len, unsigned char *bytes, size_t bytes_len) { - size_t new_len = *buf_len + bytes_len; +void bs_append_bytes(bs *b, unsigned char *bytes, size_t bytes_len) { + size_t new_len = 0, b_len = 0, b_size = 0; - if (buffer == NULL) + if ((b == NULL) || (bytes == NULL) || (bytes_len == 0)) return; + b_len = b->len; + b_size = b->size; + new_len = b_len + bytes_len; + /* Ensure that the new length does not cause an integer overflow. */ - if ((new_len < *buf_len) || (new_len < bytes_len)) { + if ((new_len < b_len) || (new_len < bytes_len)) { fprintf(stderr, OVERFLOW_MESSAGE); exit(-1); } /* If the buffer needs re-sizing... */ - if (new_len > *buf_size) { - + if (new_len > b_size) { /* Double the size of the buffer until it is larger than what we need right now. */ - while (new_len > *buf_size) { + while (new_len > b_size) { /* Ensure we don't overflow the length. */ - if ((size_t)(*buf_len * 2) < *buf_len) { + if ((b_len * 2) < b_len) { fprintf(stderr, OVERFLOW_MESSAGE); exit(-1); } - *buf_size = *buf_size * 2; + b_size = b_size * 2; } /* Extend the buffer's size. */ - *buffer = realloc(*buffer, *buf_size); - if (*buffer == NULL) { + b->buf = realloc(b->buf, b_size); + if (b->buf == NULL) { fprintf(stderr, "Failed to resize buffer.\n"); exit(-1); } + b->size = b_size; /* Zero out the extended buffer region; leave the existing bytes intact. */ - memset(*buffer + *buf_len, 0, *buf_size - *buf_len); + memset(b->buf + b_len, 0, b_size - b_len); } /* Copy the new bytes into the buffer right after the existing bytes. */ - memcpy(*buffer + *buf_len, bytes, bytes_len); + memcpy(b->buf + b_len, bytes, bytes_len); /* Update the number of used bytes in the buffer. */ - *buf_len = new_len; + b->len = new_len; +} + +/* Appends a uint32_t to the byte string. */ +void bs_append_uint32_t(bs *b, uint32_t u) { + bs_append_bytes(b, (unsigned char *)&u, sizeof(uint32_t)); +} + +/* Converts an unsigned short to network-order, then appends it to the byte string. */ +void bs_append_ushort(bs *b, unsigned short us) { + uint16_t u16 = htons(us); + bs_append_bytes(b, (unsigned char *)&u16, sizeof(uint16_t)); +} + +/* Appends one byte string (src) to another (dst). */ +void bs_append_bs(bs *dst, bs *src) { + if (src == NULL) + return; + + bs_append_bytes(dst, src->buf, src->len); +} + +/* Returns the number of bytes in this byte string. */ +size_t bs_get_len(bs *b) { + if (b == NULL) + return 0; + + return b->len; } -/* Convert an unsigned short to network-order, then append it to the buffer. See documentation for buffer_append_bytes() for description of other arguments. */ -void buffer_append_ushort(unsigned char **buffer, size_t *buf_size, size_t *buf_len, unsigned short s) { - unsigned short network_short = htons(s); - buffer_append_bytes(buffer, buf_size, buf_len, (unsigned char *)&network_short, sizeof(unsigned short)); +/* Returns the number of bytes allocated in the underlying byte string. */ +size_t bs_get_size(bs *b) { + if (b == NULL) + return 0; + + return b->size; } -/* Append a uint32_t to the buffer. See documentation for buffer_append_bytes() for description of other arguments. */ -void buffer_append_uint32_t(unsigned char **buffer, size_t *buf_size, size_t *buf_len, uint32_t i) { - buffer_append_bytes(buffer, buf_size, buf_len, (unsigned char *)&i, sizeof(uint32_t)); +/* Gets the bytes of this byte string. The caller must _never_ free it directly themselves. */ +unsigned char *bs_get_bytes(bs *b) { + if (b == NULL) + return NULL; + + return b->buf; } -/* Sets the 'ciphersuite_list' arg to a buffer (which must be free()'ed) of ciphersuites for a given TLS version, and sets the 'ciphersuite_list_len' arg to the number of bytes in 'ciphersuite_list'. When 'type' is CIPHERSUITES_MISSING, then a list of all ciphersuites missing in OpenSSL is returned. When set to CIPHERSUITES_TLSV1_3_ALL, all TLSv1.3 ciphersuites are returned only. */ +/* Gets a single byte from the offset position. Performs safety checks that the read will not overflow. Returns 0 if out of bounds. */ +unsigned char bs_get_byte(bs *b, size_t offset) { + if ((b == NULL) || (offset >= b->len)) + return 0; + + return b->buf[offset]; +} + +/* Gets a single byte from the offset position. Performs safety checks that the read will not overflow. */ +void bs_set_byte(bs *b, size_t offset, unsigned char byte) { + if ((b == NULL) || (offset >= b->len)) + return; + + b->buf[offset] = byte; +} + +/* Sets a length field in a TLS packet at the specified offset. */ +void bs_set_ushort(bs *b, size_t offset, ushort length) { + uint16_t u = htons(length); + + bs_set_byte(b, offset, (unsigned char)u); + bs_set_byte(b, offset + 1, (unsigned char)(u >> 8)); +} + +/* Reads the specified number of bytes from socket s into byte string b. Returns 0 on success, or errno on error. */ +int bs_read_socket(bs *b, int s, size_t num_bytes) { + int ret = -1, n = 0; + unsigned int i = 0; + size_t old_len = 0, bytes_read = 0; + + if (b == NULL) + return -1; + + /* Append num_bytes to the byte string to ensure that the underlying buffer is resized appropriately. Then reset the length. */ + old_len = b->len; + for (; i < (num_bytes / sizeof(uint32_t)) + 1; i++) + bs_append_uint32_t(b, 0); + + b->len = old_len; + + /* Read in num_bytes from the socket and store it in the underlying buffer. */ + bytes_read = 0; + while (bytes_read < num_bytes) { + n = recv(s, b->buf + b->len + bytes_read, num_bytes - bytes_read, 0); + if (n <= 0) { + if ((errno != 0) && (errno != ECONNRESET)) + ret = errno; + + b->len += bytes_read; + goto err; + } + bytes_read += n; + } + b->len += bytes_read; + ret = 0; + +err: + return ret; +} + +/* Returns a byte string, ciphersuite_list, with a list of ciphersuites for a given TLS version. When 'type' is CIPHERSUITES_MISSING, then a list of all ciphersuites missing in OpenSSL is returned. When set to CIPHERSUITES_TLSV1_3_ALL, all TLSv1.3 ciphersuites are returned only. */ #define CIPHERSUITES_MISSING 0 #define CIPHERSUITES_TLSV1_3_ALL 1 -void makeCiphersuiteList(unsigned char **ciphersuite_list, size_t *ciphersuite_list_len, unsigned int tls_version, unsigned int type) { +bs *makeCiphersuiteList(unsigned int tls_version, unsigned int type) { size_t ciphersuite_list_size = 1024; + bs *ciphersuite_list = NULL; // Make the buffer much smaller if we're just returning the list of 5 TLSv1.3 ciphers. if (type == CIPHERSUITES_TLSV1_3_ALL) ciphersuite_list_size = 16; - *ciphersuite_list = calloc(ciphersuite_list_size, sizeof(unsigned char)); - if (*ciphersuite_list == NULL) { - fprintf(stderr, "Failed to create buffer for ciphersuite list.\n"); - exit(-1); - } - *ciphersuite_list_len = 0; + bs_new_size(&ciphersuite_list, ciphersuite_list_size); if (type == CIPHERSUITES_MISSING) { if (tls_version == 0) @@ -4504,11 +4645,11 @@ void makeCiphersuiteList(unsigned char **ciphersuite_list, size_t *ciphersuite_l for (int i = 0; i < (sizeof(missing_ciphersuites) / sizeof(struct missing_ciphersuite)); i++) { /* Append only those that OpenSSL does not cover, and those that were not already accepted through a previous run. */ if ((missing_ciphersuites[i].check_tls_versions & tls_version) && ((missing_ciphersuites[i].accepted_tls_versions & tls_version) == 0)) { - buffer_append_ushort(ciphersuite_list, &ciphersuite_list_size, ciphersuite_list_len, missing_ciphersuites[i].id); + bs_append_ushort(ciphersuite_list, missing_ciphersuites[i].id); } } } else if (type == CIPHERSUITES_TLSV1_3_ALL) { - buffer_append_bytes(ciphersuite_list, &ciphersuite_list_size, ciphersuite_list_len, (unsigned char []) { + bs_append_bytes(ciphersuite_list, (unsigned char []) { 0x13, 0x01, // TLS_AES_128_GCM_SHA256 0x13, 0x02, // TLS_AES_256_GCM_SHA384 0x13, 0x03, // TLS_CHACHA20_POLY1305_SHA256 @@ -4516,6 +4657,8 @@ void makeCiphersuiteList(unsigned char **ciphersuite_list, size_t *ciphersuite_l 0x13, 0x05, // TLS_AES_128_CCM_8_SHA256 }, 10); } + + return ciphersuite_list; } /* Marks a ciphersuite as found so that it is not re-tested again. */ @@ -4547,42 +4690,29 @@ char *resolveCipherID(unsigned short cipher_id, int *cipher_bits) { return "UNKNOWN_CIPHER"; } -/* Sets a length field in a TLS packet at the specified offset. */ -void setTLSLength(unsigned char *buf, unsigned int offset, unsigned int length) { - uint16_t u = htons(length); - memcpy(buf + offset, &u, sizeof(u)); -} - /* Creates a basic set of TLS extensions, including SNI, ec_point_formats, Session Ticket TLS, and signature_algorithms. */ -unsigned char *makeTLSExtensions(size_t *tls_extensions_size, size_t *tls_extensions_len, struct sslCheckOptions *options) { - unsigned char *tls_extensions = NULL; +bs *makeTLSExtensions(struct sslCheckOptions *options) { + bs *tls_extensions = NULL; - - *tls_extensions_size = 64; - tls_extensions = calloc(*tls_extensions_size, sizeof(unsigned char)); - if (tls_extensions == NULL) { - fprintf(stderr, "Failed to allocate buffers for TLS extensions.\n"); - exit(-1); - } - *tls_extensions_len = 0; + bs_new_size(&tls_extensions, 64); /* Add the length of the extensions (to be filled in later). */ - buffer_append_ushort(&tls_extensions, tls_extensions_size, tls_extensions_len, 0); + bs_append_ushort(tls_extensions, 0); /* Extension: server name */ uint16_t sni_length = strlen(options->sniname); uint16_t sni_list_length = sni_length + 3; uint16_t extension_length = sni_list_length + 2; - buffer_append_ushort(&tls_extensions, tls_extensions_size, tls_extensions_len, 0x0000); /* Extension: server_name */ - buffer_append_ushort(&tls_extensions, tls_extensions_size, tls_extensions_len, extension_length); - buffer_append_ushort(&tls_extensions, tls_extensions_size, tls_extensions_len, sni_list_length); - buffer_append_bytes(&tls_extensions, tls_extensions_size, tls_extensions_len, (unsigned char []) { 0x00 /* Server Name Type: host_name */ }, 1); - buffer_append_ushort(&tls_extensions, tls_extensions_size, tls_extensions_len, sni_length); /* The length of the hostname. */ - buffer_append_bytes(&tls_extensions, tls_extensions_size, tls_extensions_len, (unsigned char *)options->sniname, sni_length); /* The hostname itself. */ + bs_append_ushort(tls_extensions, 0x0000); /* Extension: server_name */ + bs_append_ushort(tls_extensions, extension_length); + bs_append_ushort(tls_extensions, sni_list_length); + bs_append_bytes(tls_extensions, (unsigned char []) { 0x00 /* Server Name Type: host_name */ }, 1); + bs_append_ushort(tls_extensions, sni_length); /* The length of the hostname. */ + bs_append_bytes(tls_extensions, (unsigned char *)options->sniname, sni_length); /* The hostname itself. */ /* Extension: ec_point_formats */ - buffer_append_bytes(&tls_extensions, tls_extensions_size, tls_extensions_len, (unsigned char []) { + bs_append_bytes(tls_extensions, (unsigned char []) { 0x00, 0x0b, // Extension: ec_point_formats (11) 0x00, 0x04, // Extension Length (4) 0x03, // EC Point Formats Length (3) @@ -4592,13 +4722,13 @@ unsigned char *makeTLSExtensions(size_t *tls_extensions_size, size_t *tls_extens }, 8); /* Extension: SessionTicket TLS */ - buffer_append_bytes(&tls_extensions, tls_extensions_size, tls_extensions_len, (unsigned char []) { + bs_append_bytes(tls_extensions, (unsigned char []) { 0x00, 0x23, // Extension: SessionTicket TLS (35) 0x00, 0x00, // Extension Length (0) }, 4); /* Extension: signature_algorithms */ - buffer_append_bytes(&tls_extensions, tls_extensions_size, tls_extensions_len, (unsigned char []) { + bs_append_bytes(tls_extensions, (unsigned char []) { 0x00, 0x0d, // Extension: signature_algorithms (13) 0x00, 0x1e, // Extension Length (30) 0x00, 0x1c, // Signature Hash Algorithms Length (28) @@ -4619,85 +4749,57 @@ unsigned char *makeTLSExtensions(size_t *tls_extensions_size, size_t *tls_extens }, 34); /* Set the extension length. */ - setTLSLength(tls_extensions, 0, *tls_extensions_len - 2); + bs_set_ushort(tls_extensions, 0, bs_get_len(tls_extensions) - 2); return tls_extensions; } /* Adds the TLS supported_versions extension, set to TLSv1.3 only. */ -void tlsExtensionAddTLSv1_3(unsigned char **tls_extensions, size_t *tls_extensions_size, size_t *tls_extensions_len) { - buffer_append_bytes(tls_extensions, tls_extensions_size, tls_extensions_len, (unsigned char []) { +void tlsExtensionAddTLSv1_3(bs *tls_extensions) { + bs_append_bytes(tls_extensions, (unsigned char []) { 0x00, 0x2b, // supported_versions (43) 0x00, 0x03, // Length 0x02, // Supported Versions Length 0x03, 0x04, // Supported Version: TLS v1.3 }, 7); - setTLSLength(*tls_extensions, 0, *tls_extensions_len - 2); + bs_set_ushort(tls_extensions, 0, bs_get_len(tls_extensions) - 2); } /* From socket s, reads a ServerHello from the network. Returns an unsigned char array on success (which the caller must free()), or NULL on failure. */ -unsigned char *getServerHello(int s, size_t *server_hello_len) { - unsigned char *server_hello = NULL; - unsigned char initial5[8] = {0}; // The initial 5 bytes of the packet. - +bs *getServerHello(int s) { + bs *server_hello = NULL; + bs_new_size(&server_hello, 512); - /* Read the first 5 bytes to get the Content Type, Version, and Length fields. */ - int bytes_read = 0, n = 0; - while (bytes_read < 5) { - n = recv(s, initial5 + bytes_read, 5 - bytes_read, 0); - if (n <= 0) { - if ((errno != 0) && (errno != ECONNRESET)) - printf_error("recv() failed while reading Server Hello: %d (%s)\n", errno, strerror(errno)); - goto err; - } - bytes_read += n; - } - *server_hello_len = bytes_read; + /* Read in the first 5 bytes to get the length of the rest of the packet. */ + int err = bs_read_socket(server_hello, s, 5); + if (err != 0) + goto err; /* Ensure that the Content Type is Handshake (22). */ - if (initial5[0] != 0x16) + if (bs_get_byte(server_hello, 0) != 0x16) goto err; /* Get the length of the Server Hello record. */ - unsigned short packet_len = (initial5[3] << 8) | initial5[4]; - - server_hello = calloc(packet_len + sizeof(initial5), sizeof(unsigned char)); - if (server_hello == NULL) { - fprintf(stderr, "Failed to create buffer for Server Hello.\n"); - exit(-1); - } + unsigned short packet_len = (bs_get_byte(server_hello, 3) << 8) | bs_get_byte(server_hello, 4); - /* Copy the initial 5 bytes into the beginning of the buffer. */ - memcpy(server_hello, initial5, *server_hello_len); - - /* Read in the Server Hello record. */ - bytes_read = 0; - while (bytes_read < packet_len) { - n = recv(s, server_hello + *server_hello_len + bytes_read, packet_len - bytes_read, 0); - if (n <= 0) { - if ((errno != 0) && (errno != ECONNRESET)) - printf_error("recv() failed while reading Server Hello: %d (%s)\n", errno, strerror(errno)); - goto err; - } - bytes_read += n; - } - *server_hello_len += bytes_read; + /* Read in the rest of the Server Hello. */ + err = bs_read_socket(server_hello, s, packet_len); + if (err != 0) + goto err; /* Ensure that the Handshake Type is Server Hello (2). */ - if (server_hello[5] != 0x02) + if (bs_get_byte(server_hello, 5) != 0x02) goto err; return server_hello; err: - FREE(server_hello); - *server_hello_len = 0; + bs_free(&server_hello); return NULL; } -/* Returns a buffer (which the caller must free()) containing a TLS Client Hello message. The number of bytes is stored in 'client_hello_len'. 'version' is set to 0 for TLSv1.0, 1 for TLSv1.1, 2, for TLSv1.2, and 3 for TLSv1.3. The specified ciphersuite list and TLS extensions will be included. */ -unsigned char *makeClientHello(size_t *client_hello_len, struct sslCheckOptions *options, unsigned int version, unsigned char *ciphersuite_list, size_t ciphersuite_list_len, unsigned char *tls_extensions, size_t tls_extensions_len) { - unsigned char *client_hello = NULL; - size_t client_hello_size = 1024; +/* Returns a byte string (which the caller must later free) containing a TLS Client Hello message. The number of bytes is stored in 'client_hello_len'. 'version' is set to 0 for TLSv1.0, 1 for TLSv1.1, 2, for TLSv1.2, and 3 for TLSv1.3. The specified ciphersuite list and TLS extensions will be included. */ +bs *makeClientHello(struct sslCheckOptions *options, unsigned int version, bs *ciphersuite_list, bs *tls_extensions) { + bs *client_hello = NULL; unsigned int tls_record_version_low_byte = 1, tls_handshake_version_low_byte = 1; time_t time_now = time(NULL); @@ -4711,16 +4813,11 @@ unsigned char *makeClientHello(size_t *client_hello_len, struct sslCheckOptions tls_handshake_version_low_byte = 3; } - /* Allocate buffers for the Client Hello and TLS extensions. */ - client_hello = calloc(client_hello_size, sizeof(unsigned char)); - if (client_hello == NULL) { - fprintf(stderr, "Failed to allocate buffer for ClientHello.\n"); - exit(-1); - } - *client_hello_len = 0; + /* Allocate byte string for the Client Hello and TLS extensions. */ + bs_new_size(&client_hello, 1024); /* Build the TLSv1 Record with the ClientHello message. */ - buffer_append_bytes(&client_hello, &client_hello_size, client_hello_len, (unsigned char []) { + bs_append_bytes(client_hello, (unsigned char []) { 0x16, // Content Type: Handshake (22) 0x03, (unsigned char)tls_record_version_low_byte, // Version: TLS 1.x 0x00, 0x00, // Length (to be filled in later) @@ -4731,46 +4828,46 @@ unsigned char *makeClientHello(size_t *client_hello_len, struct sslCheckOptions /* "Random" 32 bytes. */ uint32_t rand = htonl(time_now); - buffer_append_uint32_t(&client_hello, &client_hello_size, client_hello_len, rand); /* The first 4 bytes is the timestamp. */ + bs_append_uint32_t(client_hello, rand); /* The first 4 bytes is the timestamp. */ for (int i = 1; i < 8; i++) { rand = rand + (time_now ^ (uint32_t)((~(i + 0) << 24) | (~(i + 1) << 16) | (~(i + 2) << 8) | (~(i + 3) << 0))); - buffer_append_uint32_t(&client_hello, &client_hello_size, client_hello_len, rand); + bs_append_uint32_t(client_hello, rand); } /* Session ID Length: 0 */ - buffer_append_bytes(&client_hello, &client_hello_size, client_hello_len, (unsigned char []) { 0x00 }, 1); + bs_append_bytes(client_hello, (unsigned char []) { 0x00 }, 1); /* Add the length (in bytes) of the ciphersuites list to the Client Hello. */ - buffer_append_ushort(&client_hello, &client_hello_size, client_hello_len, ciphersuite_list_len); + bs_append_ushort(client_hello, bs_get_len(ciphersuite_list)); /* Add the ciphersuite list. */ - buffer_append_bytes(&client_hello, &client_hello_size, client_hello_len, ciphersuite_list, ciphersuite_list_len); + bs_append_bs(client_hello, ciphersuite_list); /* Add the compression options. */ - buffer_append_bytes(&client_hello, &client_hello_size, client_hello_len, (unsigned char []) { + bs_append_bytes(client_hello, (unsigned char []) { 0x01, // Compression Methods Length (1) 0x00 // Compression Method: null (0) }, 2); /* Add the extensions to the Client Hello. */ - buffer_append_bytes(&client_hello, &client_hello_size, client_hello_len, tls_extensions, tls_extensions_len); + bs_append_bs(client_hello, tls_extensions); /* Set the length of the Client Hello. */ - client_hello[6] = 0; - setTLSLength(client_hello, 7, *client_hello_len - 9); + bs_set_byte(client_hello, 6, 0); + bs_set_ushort(client_hello, 7, bs_get_len(client_hello) - 9); /* Set the length of the Record Layer. */ - setTLSLength(client_hello, 3, *client_hello_len - 5); + bs_set_ushort(client_hello, 3, bs_get_len(client_hello) - 5); return client_hello; } /* Checks all ciphersuites that OpenSSL does not support. When version is 0, TLSv1.0 is tested. When set to 1, TLSv1.1 is tested. When set to 2, TLSv1.2 is tested. */ int testMissingCiphers(struct sslCheckOptions *options, unsigned int version) { int ret = false, s = 0; - unsigned char *ciphersuite_list = NULL, *client_hello = NULL, *server_hello = NULL, *tls_extensions = NULL; unsigned int tls_version_low_byte = 1; char *tls_printable_name = "TLSv1.0"; + bs *client_hello = NULL, *server_hello = NULL, *ciphersuite_list = NULL, *tls_extensions = NULL; tls_version_low_byte += version; @@ -4783,18 +4880,16 @@ int testMissingCiphers(struct sslCheckOptions *options, unsigned int version) { /* Continue until a Server Hello isn't received. */ while (1) { int cipher_bits = -1; - size_t client_hello_len = 0, ciphersuite_list_len = 0, tls_extensions_size = 256, tls_extensions_len = 0; - unsigned char *client_hello = NULL, *tls_extensions = NULL; char *cipher_name = NULL; struct timeval tval_start = {0}, tval_end = {0}, tval_elapsed = {0}; gettimeofday(&tval_start, NULL); - tls_extensions = makeTLSExtensions(&tls_extensions_size, &tls_extensions_len, options); + tls_extensions = makeTLSExtensions(options); /* Extension: supported_groups */ - buffer_append_bytes(&tls_extensions, &tls_extensions_size, &tls_extensions_len, (unsigned char []) { + bs_append_bytes(tls_extensions, (unsigned char []) { 0x00, 0x0a, // Extension: supported_groups (10) 0x00, 0x1c, // Extension Length (28) 0x00, 0x1a, // Supported Groups List Length (26) @@ -4813,19 +4908,14 @@ int testMissingCiphers(struct sslCheckOptions *options, unsigned int version) { 0x00, 0x0a, // sect283r1 }, 32); - setTLSLength(tls_extensions, 0, tls_extensions_len - 2); + bs_set_ushort(tls_extensions, 0, bs_get_len(tls_extensions) - 2); /* Construct the list of all ciphersuites not implemented by OpenSSL. */ - makeCiphersuiteList(&ciphersuite_list, &ciphersuite_list_len, version, CIPHERSUITES_MISSING); + ciphersuite_list = makeCiphersuiteList(version, CIPHERSUITES_MISSING); - client_hello = makeClientHello(&client_hello_len, options, version, ciphersuite_list, ciphersuite_list_len, tls_extensions, tls_extensions_len); - - FREE(ciphersuite_list); - ciphersuite_list_len = 0; - - FREE(tls_extensions); - tls_extensions_size = 0; - tls_extensions_len = 0; + client_hello = makeClientHello(options, version, ciphersuite_list, tls_extensions); + bs_free(&ciphersuite_list); + bs_free(&tls_extensions); /* Now connect to the target server. */ s = tcpConnect(options); @@ -4833,32 +4923,30 @@ int testMissingCiphers(struct sslCheckOptions *options, unsigned int version) { goto done; /* Send the Client Hello message. */ - if (send(s, client_hello, client_hello_len, 0) <= 0) { + if (send(s, bs_get_bytes(client_hello), bs_get_len(client_hello), 0) <= 0) { printf_error("send() failed while sending Client Hello: %d (%s)\n", errno, strerror(errno)); goto done; /* Returns false. */ } - FREE(client_hello); - client_hello_len = 0; + bs_free(&client_hello); - size_t server_hello_len = 0; - server_hello = getServerHello(s, &server_hello_len); + server_hello = getServerHello(s); /* If we don't receive a proper Server Hello message, or its too short, abort. We need to reach at least the session ID field (offset 44). */ - if ((server_hello == NULL) || (server_hello_len < 44)) + if ((server_hello == NULL) || (bs_get_len(server_hello) < 44)) goto done; /* Close the socket, since we're done reading. */ CLOSE(s); /* Check that the TLS version returned is what we sent earlier. */ - if ((server_hello[1] != 0x03) || (server_hello[2] != (unsigned char)tls_version_low_byte)) + if ((bs_get_byte(server_hello, 1) != 0x03) || (bs_get_byte(server_hello, 2) != (unsigned char)tls_version_low_byte)) goto done; /* At this point, the test is considered a success, even if the server rejects our Client Hello. */ ret = true; /* Get the length of the session ID. We must jump over this to reach the ciphersuite selected by the server. */ - unsigned int session_id_len = server_hello[43]; + unsigned int session_id_len = bs_get_byte(server_hello, 43); /* Its impossible for one byte to overflow an unsigned int (on any modern hardware), but still... */ if ((session_id_len + 43 + 2 + 1) < session_id_len) { @@ -4867,16 +4955,15 @@ int testMissingCiphers(struct sslCheckOptions *options, unsigned int version) { } /* Check that the session ID length wouldn't put us past our buffer boundary. */ - if ((session_id_len + 43 + 2 + 1) > server_hello_len) { + if ((session_id_len + 43 + 2 + 1) > bs_get_len(server_hello)) { fprintf(stderr, "Error: size of server_hello (%"SIZE_T_FMT") is not large enough to reach cipher suite (%u).\n", sizeof(server_hello), session_id_len + 43 + 2); exit(-1); } /* Extract the cipher ID. */ - unsigned short cipher_id = (server_hello[session_id_len + 43 + 1] << 8) | server_hello[session_id_len + 43 + 2]; + unsigned short cipher_id = (bs_get_byte(server_hello, session_id_len + 43 + 1) << 8) | bs_get_byte(server_hello, session_id_len + 43 + 2); - FREE(server_hello); - server_hello_len = 0; + bs_free(&server_hello); /* Mark this cipher ID as supported by the server, so when we loop again, the next ciphersuite list doesn't include it. */ markFoundCiphersuite(cipher_id, version); @@ -4895,10 +4982,10 @@ int testMissingCiphers(struct sslCheckOptions *options, unsigned int version) { done: CLOSE(s); - FREE(ciphersuite_list); - FREE(tls_extensions); - FREE(client_hello); - FREE(server_hello); + bs_free(&ciphersuite_list); + bs_free(&tls_extensions); + bs_free(&client_hello); + bs_free(&server_hello); return ret; } @@ -4938,12 +5025,11 @@ int testSupportedGroups(struct sslCheckOptions *options) { unsigned int printed_header = 0; int s = 0; - unsigned char *client_hello = NULL, *ciphersuite_list = NULL, *tls_extensions = NULL, *server_hello = NULL, *key_exchange = NULL; - size_t client_hello_len = 0, tls_extensions_size = 0, tls_extensions_len = 0, ciphersuite_list_len = 0, server_hello_len = 0, key_exchange_len = 0; + bs *client_hello = NULL, *ciphersuite_list = NULL, *tls_extensions = NULL, *server_hello = NULL, *key_exchange = NULL; /* Get all TLSv1.3 ciphersuites. */ - makeCiphersuiteList(&ciphersuite_list, &ciphersuite_list_len, 3, CIPHERSUITES_TLSV1_3_ALL); + ciphersuite_list = makeCiphersuiteList(3, CIPHERSUITES_TLSV1_3_ALL); /* For each key exchange group... */ for (int i = 0; i < (sizeof(group_key_exchanges) / sizeof(struct group_key_exchange)); i++) { @@ -4953,31 +5039,27 @@ int testSupportedGroups(struct sslCheckOptions *options) { unsigned int group_bit_strength = group_key_exchanges[i].group_bit_strength; int nid = group_key_exchanges[i].nid; unsigned nid_type = group_key_exchanges[i].nid_type; - key_exchange_len = group_key_exchanges[i].key_exchange_len; + uint16_t key_exchange_len = group_key_exchanges[i].key_exchange_len; /* This will hold the key exchange data that we send to the server. */ - key_exchange = calloc(key_exchange_len, sizeof(unsigned char)); - if (key_exchange == NULL) { - fprintf(stderr, "Failed to create buffer for key exchange.\n"); - exit(-1); - } + bs_new_size(&key_exchange, key_exchange_len); /* Generate the right type of key exchange data. */ if (nid_type == NID_TYPE_NA) { /* Generate "random" data. X25519 and X448 public keys have no discernible structure. */ srand(time(NULL) ^ 0xdeadbeef); - for (int j = 0; j < key_exchange_len; j++) - key_exchange[j] = rand(); + for (int j = 0; j < key_exchange_len; j++) { + unsigned char c = (unsigned char)rand(); + bs_append_bytes(key_exchange, &c, 1); + } } else if (nid_type == NID_TYPE_ECDHE) { - /* Free the buffer, since we will dynamically get the size we need and create a new one. */ - FREE(key_exchange); key_exchange_len = 0; /* Generate the ECDHE key. */ EC_KEY *key = EC_KEY_new_by_curve_name(nid); if ((key == NULL) || (EC_KEY_generate_key(key) != 1)) { - EC_KEY_free(key); key = NULL; + EC_KEY_free(key); key = NULL; fprintf(stderr, "Failed to generate ECDHE key for nid %d\n", nid); continue; } @@ -4986,18 +5068,12 @@ int testSupportedGroups(struct sslCheckOptions *options) { unsigned char *kex_buf = NULL; key_exchange_len = EC_KEY_key2buf(key, POINT_CONVERSION_UNCOMPRESSED, &kex_buf, NULL); if (kex_buf == NULL) { - EC_KEY_free(key); key = NULL; - fprintf(stderr, "Failed to obtain ECDHE public key bytes.\n"); - continue; + EC_KEY_free(key); key = NULL; + fprintf(stderr, "Failed to obtain ECDHE public key bytes.\n"); + continue; } - /* The byte array created above needs to be freed with OPENSSL_free(), not free(). To simplify the code, we will copy the bytes to our own array and call OPENSSL_free() immediately. */ - key_exchange = calloc(key_exchange_len, sizeof(unsigned char)); - if (key_exchange == NULL) { - fprintf(stderr, "Failed to create buffer for key exchange.\n"); - exit(-1); - } - memcpy(key_exchange, kex_buf, key_exchange_len); + bs_append_bytes(key_exchange, kex_buf, key_exchange_len); OPENSSL_free(kex_buf); kex_buf = NULL; EC_KEY_free(key); key = NULL; @@ -5006,60 +5082,70 @@ int testSupportedGroups(struct sslCheckOptions *options) { /* The value (Y) for FFDHE group must be 1 < Y < p - 1 (see RFC7919). Furthermore, GnuTLS checks that Y ^ q mod p == 1 (see GnuTLS v3.6.11.1, lib/nettle/pk.c:291). The easiest way to do this seems to be to actually generate real DH public keys. */ DH *dh = DH_new_by_nid(nid); if (!DH_generate_key(dh)) { - FREE(key_exchange); - fprintf(stderr, "Failed to generate DH key for nid %d\n", nid); - continue; + bs_free(&key_exchange); + fprintf(stderr, "Failed to generate DH key for nid %d\n", nid); + continue; + } + + /* Make array to read in DH public key. */ + unsigned int bytes_len = key_exchange_len; + unsigned char *bytes = calloc(bytes_len, sizeof(unsigned char)); + if (bytes == NULL) { + fprintf(stderr, "Failed to allocate buffer for key.\n"); + exit(-1); } - /* Export the public key to our byte array. */ + /* Export the public key to our array. */ const BIGNUM *pub_key = NULL; DH_get0_key(dh, &pub_key, NULL); - if (!BN_bn2binpad(pub_key, key_exchange, key_exchange_len)) { - FREE(key_exchange); - fprintf(stderr, "Failed to get DH key for nid %d\n", nid); - continue; + if (!BN_bn2binpad(pub_key, bytes, bytes_len)) { + bs_free(&key_exchange); + fprintf(stderr, "Failed to get DH key for nid %d\n", nid); + continue; } + /* Add the bytes to our byte string. */ + bs_append_bytes(key_exchange, bytes, bytes_len); + FREE(bytes); bytes_len = 0; + } else { /* Use the provided value, since it must be a specific format. */ - //memcpy(key_exchange, group_key_exchanges[i].key_exchange, key_exchange_len); fprintf(stderr, "Error: unknown NID_TYPE in struct: %d\n", nid_type); exit(-1); } /* Make generic TLS extensions (with SNI, accepted EC point formats, etc). */ - tls_extensions = makeTLSExtensions(&tls_extensions_size, &tls_extensions_len, options); + tls_extensions = makeTLSExtensions(options); /* Add the supported_versions extension to signify we are using TLS v1.3. */ - tlsExtensionAddTLSv1_3(&tls_extensions, &tls_extensions_size, &tls_extensions_len); + tlsExtensionAddTLSv1_3(tls_extensions); /* Add the supported_groups extension. Only add the one group we are testing for. */ - buffer_append_bytes(&tls_extensions, &tls_extensions_size, &tls_extensions_len, (unsigned char []) { + bs_append_bytes(tls_extensions, (unsigned char []) { 0x00, 0x0a, // Extension Type: supported_groups (10) 0x00, 0x04, // Extension Length (4) 0x00, 0x02, // Supported Groups List Length (2) }, 6); - buffer_append_ushort(&tls_extensions, &tls_extensions_size, &tls_extensions_len, group_id); + bs_append_ushort(tls_extensions, group_id); /* Add the key_share extension for the current group type. */ - buffer_append_bytes(&tls_extensions, &tls_extensions_size, &tls_extensions_len, (unsigned char []) { 0x00, 0x33 }, 2); // Extension Type: key_share (51) - buffer_append_ushort(&tls_extensions, &tls_extensions_size, &tls_extensions_len, key_exchange_len + 6); // Extension Length - buffer_append_ushort(&tls_extensions, &tls_extensions_size, &tls_extensions_len, key_exchange_len + 4); // Client Key Share Length - buffer_append_ushort(&tls_extensions, &tls_extensions_size, &tls_extensions_len, group_id); // Group ID. - buffer_append_ushort(&tls_extensions, &tls_extensions_size, &tls_extensions_len, key_exchange_len); // Key Exchange Length - buffer_append_bytes(&tls_extensions, &tls_extensions_size, &tls_extensions_len, key_exchange, key_exchange_len); // Key Exchange + bs_append_bytes(tls_extensions, (unsigned char []) { 0x00, 0x33 }, 2); // Extension Type: key_share (51) + bs_append_ushort(tls_extensions, bs_get_len(key_exchange) + 6); // Extension Length + bs_append_ushort(tls_extensions, bs_get_len(key_exchange) + 4); // Client Key Share Length + bs_append_ushort(tls_extensions, group_id); // Group ID. + bs_append_ushort(tls_extensions, bs_get_len(key_exchange)); // Key Exchange Length + bs_append_bs(tls_extensions, key_exchange); // Key Exchange - FREE(key_exchange); - key_exchange_len = 0; + bs_free(&key_exchange); /* Update the TLS extensions length since we manually added to it. */ - setTLSLength(tls_extensions, 0, tls_extensions_len - 2); + bs_set_ushort(tls_extensions, 0, bs_get_len(tls_extensions) - 2); - client_hello = makeClientHello(&client_hello_len, options, 3, ciphersuite_list, ciphersuite_list_len, tls_extensions, tls_extensions_len); + /* Create the Client Hello buffer using the ciphersuite list and TLS extensions. */ + client_hello = makeClientHello(options, 3, ciphersuite_list, tls_extensions); - FREE(tls_extensions); - tls_extensions_size = 0; - tls_extensions_len = 0; + /* Free the TLS extensions since we're done with them. Note: we don't free the ciphersuite_list because we'll need them on the next loop. */ + bs_free(&tls_extensions); /* Now connect to the target server. */ s = tcpConnect(options); @@ -5069,23 +5155,21 @@ int testSupportedGroups(struct sslCheckOptions *options) { } /* Send the Client Hello message. */ - if (send(s, client_hello, client_hello_len, 0) <= 0) { + if (send(s, bs_get_bytes(client_hello), bs_get_len(client_hello), 0) <= 0) { printf_error("send() failed while sending Client Hello: %d (%s)\n", errno, strerror(errno)); ret = false; goto done; } - FREE(client_hello); - client_hello_len = 0; + bs_free(&client_hello); - server_hello = getServerHello(s, &server_hello_len); + server_hello = getServerHello(s); CLOSE(s); /* This group is not supported. */ if (server_hello == NULL) continue; - FREE(server_hello); - server_hello_len = 0; + bs_free(&server_hello); if (!printed_header) { printf("\n %sServer Key Exchange Group(s):%s\n", COL_BLUE, RESET); @@ -5097,18 +5181,10 @@ int testSupportedGroups(struct sslCheckOptions *options) { done: CLOSE(s); - FREE(ciphersuite_list); - ciphersuite_list_len = 0; - - FREE(tls_extensions); - tls_extensions_size = 0; - tls_extensions_len = 0; - - FREE(client_hello); - client_hello_len = 0; - - FREE(server_hello); - server_hello_len = 0; + bs_free(&ciphersuite_list); + bs_free(&tls_extensions); + bs_free(&client_hello); + bs_free(&server_hello); return ret; } diff --git a/sslscan.h b/sslscan.h index 2a7087f..8a65c31 100644 --- a/sslscan.h +++ b/sslscan.h @@ -263,6 +263,14 @@ struct ocsp_cert_id_st { ASN1_INTEGER serialNumber; }; +#define BS_DEFAULT_NEW_SIZE 256 /* The starting size of the buffer when bs_new() is used. */ +struct _bs { + unsigned char *buf; + size_t size; /* The size of the allocated buffer. */ + size_t len; /* The number of bytes currently in the buffer. */ +}; +typedef struct _bs bs; /* Stands for 'byte string'. */ + /* We redefine these so that we can run correctly even if the vendor gives us * a version of OpenSSL that does not match its header files. (Apple: I am * looking at you.) @@ -275,9 +283,19 @@ struct ocsp_cert_id_st { #endif // Utilities -void buffer_append_bytes(unsigned char **buffer, size_t *buf_size, size_t *buf_len, unsigned char *bytes, size_t bytes_len); -void buffer_append_ushort(unsigned char **buffer, size_t *buf_size, size_t *buf_len, unsigned short s); -void buffer_append_uint32_t(unsigned char **buffer, size_t *buf_size, size_t *buf_len, uint32_t i); +void bs_new(bs **); +void bs_new_size(bs **, size_t); +void bs_free(bs **); +void bs_append_bytes(bs *, unsigned char *, size_t); +void bs_append_uint32_t(bs *, uint32_t); +void bs_append_ushort(bs *, unsigned short); +void bs_append_bs(bs *, bs *); +size_t bs_get_len(bs *); +size_t bs_get_size(bs *); +unsigned char *bs_get_bytes(bs *); +unsigned char bs_get_byte(bs *, size_t); +void bs_set_byte(bs *, size_t, unsigned char); +int bs_read_socket(bs *b, int s, size_t num_bytes); SSL_CTX *CTX_new(const SSL_METHOD *method); int fileExists(char *); void findMissingCiphers(); From fba313a59c6c79dc93cee976e9474ef0f8097ca5 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Sat, 14 Dec 2019 22:37:49 -0500 Subject: [PATCH 37/52] Fixed Windows builds. --- sslscan.c | 2 +- sslscan.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/sslscan.c b/sslscan.c index 5627f58..ac01cb3 100644 --- a/sslscan.c +++ b/sslscan.c @@ -4577,7 +4577,7 @@ void bs_set_byte(bs *b, size_t offset, unsigned char byte) { } /* Sets a length field in a TLS packet at the specified offset. */ -void bs_set_ushort(bs *b, size_t offset, ushort length) { +void bs_set_ushort(bs *b, size_t offset, unsigned short length) { uint16_t u = htons(length); bs_set_byte(b, offset, (unsigned char)u); diff --git a/sslscan.h b/sslscan.h index 8a65c31..1517b99 100644 --- a/sslscan.h +++ b/sslscan.h @@ -295,6 +295,7 @@ size_t bs_get_size(bs *); unsigned char *bs_get_bytes(bs *); unsigned char bs_get_byte(bs *, size_t); void bs_set_byte(bs *, size_t, unsigned char); +void bs_set_ushort(bs *b, size_t offset, unsigned short length); int bs_read_socket(bs *b, int s, size_t num_bytes); SSL_CTX *CTX_new(const SSL_METHOD *method); int fileExists(char *); From 3945cc5ceed45150cd014e9119dd4627d3d5ce2b Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Sun, 15 Dec 2019 11:10:12 -0500 Subject: [PATCH 38/52] Colors are now enabled on Cygwin terminals. Line buffering is enabled on them as well, resulting in much better responsiveness during scans. --- sslscan.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/sslscan.c b/sslscan.c index ac01cb3..76c1995 100644 --- a/sslscan.c +++ b/sslscan.c @@ -3573,6 +3573,7 @@ int main(int argc, char *argv[]) int err; HANDLE hConsole; DWORD consoleMode; + unsigned int enable_colors; #endif // Init... @@ -3618,8 +3619,28 @@ int main(int argc, char *argv[]) #ifdef _WIN32 /* Attempt to enable console colors. This succeeds in Windows 10. For other * OSes, color is disabled. */ + enable_colors = 1; hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - if ((hConsole == INVALID_HANDLE_VALUE) || (!GetConsoleMode(hConsole, &consoleMode)) || (!SetConsoleMode(hConsole, consoleMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING))) { + + /* Cygwin's terminal is re-directed, so GetConsoleMode() fails on it. So we'll try to get a direct handle in that case. */ + if (!GetConsoleMode(hConsole, &consoleMode)) { + hConsole = CreateFile("CONIN$", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + /* Also, Cygwin appears to do full buffering of output, so the program seems to hang until its fully complete, then the output gets dumped all at once. To be more responsive, we'll force line buffering at 80 bytes (the default terminal width). */ + setvbuf(stdout, NULL, _IOLBF, 80); + + /* If we still can't get console information, then disable colors. */ + if (!GetConsoleMode(hConsole, &consoleMode)) + enable_colors = 0; + } + + /* Some terminals already have colors enabled, and somehow don't like being set. */ + if (enable_colors && ((consoleMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0)) { + if (!SetConsoleMode(hConsole, consoleMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) + enable_colors = 0; + } + + if (!enable_colors) { RESET = ""; COL_RED = ""; COL_YELLOW = ""; From 5f5c647cab1b658336c63e70744e6807244a2dc2 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Sun, 15 Dec 2019 15:35:20 -0500 Subject: [PATCH 39/52] Discovered key exchange group's ID now included in XML. --- sslscan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sslscan.c b/sslscan.c index 76c1995..b99d48e 100644 --- a/sslscan.c +++ b/sslscan.c @@ -5197,7 +5197,7 @@ int testSupportedGroups(struct sslCheckOptions *options) { printed_header = 1; } printf("%s%s%s (%d bits)\n", color, group_name, RESET, group_bit_strength); - printf_xml(" \n", group_bit_strength, group_name); + printf_xml(" \n", group_bit_strength, group_name, group_id); } done: From b0504c90b8e9f94603e4e76877b4287b39f6b01a Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Sun, 22 Dec 2019 14:23:03 -0500 Subject: [PATCH 40/52] Added signature algorithm enumeration for TLSv1.3. --- docker_test.sh | 14 +- docker_test/cert_ecdsa_prime256v1.crt | 20 +++ docker_test/expected_output/test_13.txt | 5 + docker_test/expected_output/test_14.txt | 5 + docker_test/expected_output/test_15.txt | 61 +++++++ docker_test/expected_output/test_4.txt | 5 + docker_test/expected_output/test_6.txt | 5 + docker_test/key_ecdsa_prime256v1.pem | 5 + docker_test/key_notes.txt | 5 +- sslscan.c | 215 +++++++++++++++++++++--- sslscan.h | 2 + 11 files changed, 315 insertions(+), 27 deletions(-) create mode 100644 docker_test/cert_ecdsa_prime256v1.crt create mode 100644 docker_test/expected_output/test_15.txt create mode 100644 docker_test/key_ecdsa_prime256v1.pem diff --git a/docker_test.sh b/docker_test.sh index 2da007c..8273cd0 100755 --- a/docker_test.sh +++ b/docker_test.sh @@ -11,7 +11,7 @@ # # For debugging purposes, here is a cheat sheet for manually running the docker image: # -# docker run -p 4443:443 --security-opt seccomp:unconfined -it sslscan-test:2 /bin/bash +# docker run -p 4443:443 --security-opt seccomp:unconfined -it sslscan-test:3 /bin/bash # # @@ -26,7 +26,7 @@ # This is the docker tag for the image. If this tag doesn't exist, then we assume the # image is out of date, and generate a new one with this tag. -IMAGE_VERSION=2 +IMAGE_VERSION=3 # This is the name of our docker image. IMAGE_NAME=sslscan-test @@ -269,6 +269,7 @@ function run_tests { run_test_12 "0" run_test_13 "0" run_test_14 "0" + run_test_15 "0" } @@ -356,6 +357,12 @@ function run_test_14 { } +# GnuTLS with an ECDSA certificate (secp256r1 / NIST P-256). +function run_test_15 { + run_test $1 '15' "/gnutls-3.6.11.1/gnutls-serv -p 443 --x509certfile=/etc/ssl/cert_ecdsa_prime256v1.crt --x509keyfile=/etc/ssl/key_ecdsa_prime256v1.pem" "" +} + + # Run a test. Set the first argument to '1' to enable test debugging. # Second argument is the test number to run. Third argument is the executable and # its args to be run inside the container.. @@ -381,6 +388,9 @@ function run_test { return fi + # Wait 250ms to ensure that the services in the container are fully initialized. + sleep 0.25 + # Run sslscan and cut out the first two lines. Those contain the version number # and local version of OpenSSL, which can change over time (and when they do, this # would break the test if they were left in). diff --git a/docker_test/cert_ecdsa_prime256v1.crt b/docker_test/cert_ecdsa_prime256v1.crt new file mode 100644 index 0000000..3cd4a48 --- /dev/null +++ b/docker_test/cert_ecdsa_prime256v1.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDVjCCAT4CCQDe1MM22vqmNTANBgkqhkiG9w0BAQsFADA/MQswCQYDVQQGEwJY +WDEeMBwGA1UECAwVTm93aGVyZSBpbiBwYXJ0aWN1bGFyMRAwDgYDVQQHDAdOb3do +ZXJlMB4XDTE5MTIyMjE5MDE1NloXDTI5MTIyMjE5MDE1NlowZjELMAkGA1UEBhMC +WFgxHjAcBgNVBAgMFU5vd2hlcmUgaW4gcGFydGljdWxhcjEQMA4GA1UEBwwHTm93 +aGVyZTElMCMGA1UEAwwcaXRzcGVhbnV0YnV0dGVyamVsbHl0aW1lLmNvbTBZMBMG +ByqGSM49AgEGCCqGSM49AwEHA0IABEJG/H34ca87RR7tz4meDGqz8sV+nSSl2+VB +JFW3M3W85C84Tlx5WG5Z16+GtpsK0hBT84wjkUo0KpPfY7/dCFYwDQYJKoZIhvcN +AQELBQADggIBAEATuWgTLHRq3+EDfJj8l5kGhvg8jjAGc/9J1i8oEwJl1Gy8Dv02 +jFu67camK09vprZ25EHzyVHUn+1PtZUi1kl/dpnBfFYADHZTOyokhIZ/QWLd1yr4 +Oc7ZHcVwODt+S/npfZsga2R66oI+wUQbkF7+/xpFU/DcjevMQkE3Ql5cMaFa5NZf +Z7adpYct7RPTW1aqPVckZbB3FfN85YpTyRVOt3u93/qG73dzIVjVg6YsjZYgtvxD +QhIQotKyAL6lIzA51KtIY0WhE2QmBB4YnIHlK1VkvvTaWk5tcBuY8Se2mBHfAyL5 +TESNfxBi884xBoHAJXkV6tZszhEJFgJi7zZS+fpP3kxst+CQBvhSa7gh6hWcqZyL +JGCUTjSUxfZEo97cKqOt8kYMls1eBYuIOUQdmcFbY8ML3O90KpLxosT9cUwsceZc +nBnF1qJwtG0o1RsnAYOLVCuZaimqor7rBGgBwBjkauR58PgQQBvMLtwj59edkkW+ +fAQ/xcI7ofETEKzoxHc1ea6LTE4ELWP58tds5URx0/aGYyMVazKZyhPDk2rh7/r3 +uo7rhOrCJBO89u7wRcbSnzxtWxYI3V8+5a/70Eh7ztIUJwOd+XehexJJvqZdeA7p +LBMjnUSNaR1BA4oNXP3vaFUgRFDf8dosmVAstzVDHQlE6l08bFZ0ovpj +-----END CERTIFICATE----- diff --git a/docker_test/expected_output/test_13.txt b/docker_test/expected_output/test_13.txt index 047dc1c..54523ca 100644 --- a/docker_test/expected_output/test_13.txt +++ b/docker_test/expected_output/test_13.txt @@ -69,6 +69,11 @@ ffdhe4096 (150 bits) ffdhe6144 (175 bits) ffdhe8192 (192 bits) + Server Signature Algorithm(s): +rsa_pss_rsae_sha256 +rsa_pss_rsae_sha384 +rsa_pss_rsae_sha512 + SSL Certificate: Signature Algorithm: sha256WithRSAEncryption RSA Key Strength: 3072 diff --git a/docker_test/expected_output/test_14.txt b/docker_test/expected_output/test_14.txt index d22696c..0ffa640 100644 --- a/docker_test/expected_output/test_14.txt +++ b/docker_test/expected_output/test_14.txt @@ -50,6 +50,11 @@ Accepted TLSv1.2 128 bits AES128-SHA secp521r1 [P-521] (256 bits) ffdhe8192 (192 bits) + Server Signature Algorithm(s): +rsa_pss_rsae_sha256 +rsa_pss_rsae_sha384 +rsa_pss_rsae_sha512 + SSL Certificate: Signature Algorithm: sha256WithRSAEncryption RSA Key Strength: 3072 diff --git a/docker_test/expected_output/test_15.txt b/docker_test/expected_output/test_15.txt new file mode 100644 index 0000000..1b0dd61 --- /dev/null +++ b/docker_test/expected_output/test_15.txt @@ -0,0 +1,61 @@ + +Connected to 127.0.0.1 + +Testing SSL server localhost on port 4443 using SNI name localhost + + TLS Fallback SCSV: +Server supports TLS Fallback SCSV + + TLS renegotiation: +Secure session renegotiation supported + + TLS Compression: +Compression disabled + + Heartbleed: +TLS 1.3 not vulnerable to heartbleed +TLS 1.2 not vulnerable to heartbleed +TLS 1.1 not vulnerable to heartbleed +TLS 1.0 not vulnerable to heartbleed + + SSL Protocols: +SSLv2 is not enabled +SSLv3 is not enabled + + Supported Server Cipher(s): +Preferred TLSv1.3 128 bits TLS_AES_128_GCM_SHA256 Curve 25519 DHE 253 +Accepted TLSv1.3 256 bits TLS_AES_256_GCM_SHA384 Curve 25519 DHE 253 +Accepted TLSv1.3 256 bits TLS_CHACHA20_POLY1305_SHA256 Curve 25519 DHE 253 +Accepted TLSv1.3 128 bits TLS_AES_128_CCM_SHA256 Curve 25519 DHE 253 +Preferred TLSv1.2 256 bits ECDHE-ECDSA-AES256-GCM-SHA384 Curve 25519 DHE 253 +Accepted TLSv1.2 256 bits ECDHE-ECDSA-CHACHA20-POLY1305 Curve 25519 DHE 253 +Accepted TLSv1.2 256 bits ECDHE-ECDSA-AES256-CCM Curve 25519 DHE 253 +Accepted TLSv1.2 128 bits ECDHE-ECDSA-AES128-GCM-SHA256 Curve 25519 DHE 253 +Accepted TLSv1.2 128 bits ECDHE-ECDSA-AES128-CCM Curve 25519 DHE 253 +Accepted TLSv1.2 256 bits ECDHE-ECDSA-AES256-SHA Curve 25519 DHE 253 +Accepted TLSv1.2 128 bits ECDHE-ECDSA-AES128-SHA Curve 25519 DHE 253 +Preferred TLSv1.1 256 bits ECDHE-ECDSA-AES256-SHA Curve 25519 DHE 253 +Accepted TLSv1.1 128 bits ECDHE-ECDSA-AES128-SHA Curve 25519 DHE 253 +Preferred TLSv1.0 256 bits ECDHE-ECDSA-AES256-SHA Curve 25519 DHE 253 +Accepted TLSv1.0 128 bits ECDHE-ECDSA-AES128-SHA Curve 25519 DHE 253 + + Server Key Exchange Group(s): +X25519 (128 bits) +secp256r1 [P-256] (128 bits) +secp384r1 [P-384] (192 bits) +secp521r1 [P-521] (256 bits) +ffdhe2048 (112 bits) +ffdhe3072 (128 bits) +ffdhe4096 (150 bits) +ffdhe6144 (175 bits) +ffdhe8192 (192 bits) + + Server Signature Algorithm(s): +ecdsa_secp256r1_sha256 + + SSL Certificate: +Signature Algorithm: sha256WithRSAEncryption +Subject: itspeanutbutterjellytime.com +Issuer: /C=XX/ST=Nowhere in particular/L=Nowhere +Not valid before: Dec 22 19:01:56 2019 GMT +Not valid after: Dec 22 19:01:56 2029 GMT diff --git a/docker_test/expected_output/test_4.txt b/docker_test/expected_output/test_4.txt index bf765b4..21c0d45 100644 --- a/docker_test/expected_output/test_4.txt +++ b/docker_test/expected_output/test_4.txt @@ -66,6 +66,11 @@ secp256r1 [P-256] (128 bits) secp384r1 [P-384] (192 bits) secp521r1 [P-521] (256 bits) + Server Signature Algorithm(s): +rsa_pss_rsae_sha256 +rsa_pss_rsae_sha384 +rsa_pss_rsae_sha512 + SSL Certificate: Signature Algorithm: sha256WithRSAEncryption RSA Key Strength: 3072 diff --git a/docker_test/expected_output/test_6.txt b/docker_test/expected_output/test_6.txt index 7d50208..9aec781 100644 --- a/docker_test/expected_output/test_6.txt +++ b/docker_test/expected_output/test_6.txt @@ -36,6 +36,11 @@ secp256r1 [P-256] (128 bits) secp384r1 [P-384] (192 bits) secp521r1 [P-521] (256 bits) + Server Signature Algorithm(s): +rsa_pss_rsae_sha256 +rsa_pss_rsae_sha384 +rsa_pss_rsae_sha512 + SSL Certificate: Signature Algorithm: sha256WithRSAEncryption RSA Key Strength: 3072 diff --git a/docker_test/key_ecdsa_prime256v1.pem b/docker_test/key_ecdsa_prime256v1.pem new file mode 100644 index 0000000..4e1a0f1 --- /dev/null +++ b/docker_test/key_ecdsa_prime256v1.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIP5zy1nQDeAkFKDZ1F/ur26G7SBeu1HbCgbNLwFVUzrroAoGCCqGSM49 +AwEHoUQDQgAEQkb8ffhxrztFHu3PiZ4MarPyxX6dJKXb5UEkVbczdbzkLzhOXHlY +blnXr4a2mwrSEFPzjCORSjQqk99jv90IVg== +-----END EC PRIVATE KEY----- diff --git a/docker_test/key_notes.txt b/docker_test/key_notes.txt index eb8b07e..005dda6 100644 --- a/docker_test/key_notes.txt +++ b/docker_test/key_notes.txt @@ -12,7 +12,10 @@ The 512, 1024, 2048, and 3072 refer to the RSA key size. To generate new keys, and sign them by the CA: -1.) Generate the key: openssl genrsa -out key.pem 1024 +1.) Generate the key. + + * For RSA keys: openssl genrsa -out key.pem 1024 + * For ECDSA keys: openssl ecparam -name prime256v1 -genkey -noout -out key.pem 2.) Make CSR: openssl req -new -key key.pem -out new.csr diff --git a/sslscan.c b/sslscan.c index b99d48e..8c11d65 100644 --- a/sslscan.c +++ b/sslscan.c @@ -3517,7 +3517,11 @@ int testHost(struct sslCheckOptions *options) // Enumerate key exchange groups. if (options->groups) - testSupportedGroups(options); + testSupportedGroups(options); + + // Enumerate signature algorithms. + if (options->signature_algorithms) + testSignatureAlgorithms(options); // Print certificate if (status == true && options->showCertificate == true) @@ -3593,6 +3597,7 @@ int main(int argc, char *argv[]) options.compression = true; options.heartbleed = true; options.groups = true; + options.signature_algorithms = true; options.starttls_ftp = false; options.starttls_imap = false; options.starttls_irc = false; @@ -3772,6 +3777,10 @@ int main(int argc, char *argv[]) else if (strcmp("--no-groups", argv[argLoop]) == 0) options.groups = false; + // Should we check for signature algorithms? + else if (strcmp("--no-sigs", argv[argLoop]) == 0) + options.signature_algorithms = false; + // StartTLS... FTP else if (strcmp("--starttls-ftp", argv[argLoop]) == 0) options.starttls_ftp = true; @@ -4063,6 +4072,7 @@ int main(int argc, char *argv[]) printf(" %s--no-compression%s Do not check for TLS compression (CRIME)\n", COL_GREEN, RESET); printf(" %s--no-heartbleed%s Do not check for OpenSSL Heartbleed (CVE-2014-0160)\n", COL_GREEN, RESET); printf(" %s--no-groups%s Do not enumerate key exchange groups\n", COL_GREEN, RESET); + printf(" %s--no-sigs%s Do not enumerate signature algorithms\n", COL_GREEN, RESET); printf(" %s--starttls-ftp%s STARTTLS setup for FTP\n", COL_GREEN, RESET); printf(" %s--starttls-imap%s STARTTLS setup for IMAP\n", COL_GREEN, RESET); printf(" %s--starttls-irc%s STARTTLS setup for IRC\n", COL_GREEN, RESET); @@ -4712,7 +4722,7 @@ char *resolveCipherID(unsigned short cipher_id, int *cipher_bits) { } /* Creates a basic set of TLS extensions, including SNI, ec_point_formats, Session Ticket TLS, and signature_algorithms. */ -bs *makeTLSExtensions(struct sslCheckOptions *options) { +bs *makeTLSExtensions(struct sslCheckOptions *options, unsigned int include_signature_algorithms) { bs *tls_extensions = NULL; bs_new_size(&tls_extensions, 64); @@ -4748,26 +4758,28 @@ bs *makeTLSExtensions(struct sslCheckOptions *options) { 0x00, 0x00, // Extension Length (0) }, 4); - /* Extension: signature_algorithms */ - bs_append_bytes(tls_extensions, (unsigned char []) { - 0x00, 0x0d, // Extension: signature_algorithms (13) - 0x00, 0x1e, // Extension Length (30) - 0x00, 0x1c, // Signature Hash Algorithms Length (28) - 0x04, 0x03, // ecdsa_secp256r1_sha256 - 0x05, 0x03, // ecdsa_secp384r1_sha384 - 0x06, 0x03, // ecdsa_secp521r1_sha512 - 0x08, 0x07, // ed25519 - 0x08, 0x08, // ed448 - 0x08, 0x09, // rsa_pss_pss_sha256 - 0x08, 0x0a, // rsa_pss_pss_sha384 - 0x08, 0x0b, // rsa_pss_pss_sha512 - 0x08, 0x04, // rsa_pss_rsae_sha256 - 0x08, 0x05, // rsa_pss_rsae_sha384 - 0x08, 0x06, // rsa_pss_rsae_sha512 - 0x04, 0x01, // rsa_pkcs1_sha256 - 0x05, 0x01, // rsa_pkcs1_sha384 - 0x06, 0x01, // rsa_pkcs1_sha512 - }, 34); + if (include_signature_algorithms) { + /* Extension: signature_algorithms */ + bs_append_bytes(tls_extensions, (unsigned char []) { + 0x00, 0x0d, // Extension: signature_algorithms (13) + 0x00, 0x1e, // Extension Length (30) + 0x00, 0x1c, // Signature Hash Algorithms Length (28) + 0x04, 0x03, // ecdsa_secp256r1_sha256 + 0x05, 0x03, // ecdsa_secp384r1_sha384 + 0x06, 0x03, // ecdsa_secp521r1_sha512 + 0x08, 0x07, // ed25519 + 0x08, 0x08, // ed448 + 0x08, 0x09, // rsa_pss_pss_sha256 + 0x08, 0x0a, // rsa_pss_pss_sha384 + 0x08, 0x0b, // rsa_pss_pss_sha512 + 0x08, 0x04, // rsa_pss_rsae_sha256 + 0x08, 0x05, // rsa_pss_rsae_sha384 + 0x08, 0x06, // rsa_pss_rsae_sha512 + 0x04, 0x01, // rsa_pkcs1_sha256 + 0x05, 0x01, // rsa_pkcs1_sha384 + 0x06, 0x01, // rsa_pkcs1_sha512 + }, 34); + } /* Set the extension length. */ bs_set_ushort(tls_extensions, 0, bs_get_len(tls_extensions) - 2); @@ -4907,7 +4919,7 @@ int testMissingCiphers(struct sslCheckOptions *options, unsigned int version) { gettimeofday(&tval_start, NULL); - tls_extensions = makeTLSExtensions(options); + tls_extensions = makeTLSExtensions(options, 1); /* Extension: supported_groups */ bs_append_bytes(tls_extensions, (unsigned char []) { @@ -5136,7 +5148,7 @@ int testSupportedGroups(struct sslCheckOptions *options) { } /* Make generic TLS extensions (with SNI, accepted EC point formats, etc). */ - tls_extensions = makeTLSExtensions(options); + tls_extensions = makeTLSExtensions(options, 1); /* Add the supported_versions extension to signify we are using TLS v1.3. */ tlsExtensionAddTLSv1_3(tls_extensions); @@ -5209,6 +5221,161 @@ int testSupportedGroups(struct sslCheckOptions *options) { return ret; } +/* Enumerates all the signature algorithms supported by the server. */ +int testSignatureAlgorithms(struct sslCheckOptions *options) { + int ret = true; + + struct signature_algorithm { + uint16_t sig_id; + char *sig_name; + char *color; + }; + +#define COL_PLAIN "" +#define BOGUS_SIG_ALG_ID 0xfdff /* Last un-assigned ID. */ + struct signature_algorithm signature_algorithms[] = { + {BOGUS_SIG_ALG_ID, "bogus", COL_RED}, /* Tests if the server is accepting all. */ + {0x0201, "rsa_pkcs1_sha1", COL_RED}, + {0x0202, "SHA1 DSA", COL_RED}, + {0x0203, "ecdsa_sha1", COL_RED}, + {0x0301, "SHA224 ECDSA", COL_YELLOW}, + {0x0302, "SHA224 DSA", COL_RED}, + {0x0303, "SHA224 ECDSA", COL_YELLOW}, + {0x0401, "rsa_pkcs1_sha256", COL_PLAIN}, + {0x0402, "SHA256 DSA", COL_RED}, + {0x0403, "ecdsa_secp256r1_sha256", COL_PLAIN}, + {0x0501, "rsa_pkcs1_sha384", COL_PLAIN}, + {0x0502, "SHA384 DSA", COL_RED}, + {0x0503, "ecdsa_secp384r1_sha384", COL_PLAIN}, + {0x0601, "rsa_pkcs1_sha512", COL_PLAIN}, + {0x0602, "SHA512 DSA", COL_RED}, + {0x0603, "ecdsa_secp521r1_sha512", COL_PLAIN}, + {0x0804, "rsa_pss_rsae_sha256", COL_PLAIN}, + {0x0805, "rsa_pss_rsae_sha384", COL_PLAIN}, + {0x0806, "rsa_pss_rsae_sha512", COL_PLAIN}, + {0x0807, "ed25519", COL_GREEN}, + {0x0808, "ed448", COL_GREEN}, + {0x0809, "rsa_pss_pss_sha256", COL_PLAIN}, + {0x080a, "rsa_pss_pss_sha384", COL_PLAIN}, + {0x080b, "rsa_pss_pss_sha512", COL_PLAIN}, + }; + + unsigned int printed_header = 0; + int s = 0; + bs *client_hello = NULL, *ciphersuite_list = NULL, *tls_extensions = NULL, *server_hello = NULL; + + + /* Get all TLSv1.3 ciphersuites. */ + ciphersuite_list = makeCiphersuiteList(3, CIPHERSUITES_TLSV1_3_ALL); + + /* For each signature algorithm... */ + for (int i = 0; i < (sizeof(signature_algorithms) / sizeof(struct signature_algorithm)); i++) { + uint16_t sig_id = signature_algorithms[i].sig_id; + char *sig_name = signature_algorithms[i].sig_name; + char *color = signature_algorithms[i].color; + + + /* Make generic TLS extensions (with SNI, accepted EC point formats, etc). */ + tls_extensions = makeTLSExtensions(options, 0); + + /* Extension: supported_groups */ + bs_append_bytes(tls_extensions, (unsigned char []) { + 0x00, 0x0a, // Extension: supported_groups (10) + 0x00, 0x16, // Extension Length (22) + 0x00, 0x14, // Supported Groups List Length (20) + 0x00, 0x17, // secp256r1 + 0x00, 0x19, // secp521r1 + 0x00, 0x18, // secp384r1 + 0x00, 0x1d, // X25519 + 0x00, 0x1e, // X448 + 0x01, 0x00, // FFDHE2048 + 0x01, 0x01, // FFDHE3072 + 0x01, 0x02, // FFDHE4096 + 0x01, 0x03, // FFDHE6144 + 0x01, 0x04, // FFDHE8192 + }, 26); + + /* Extension: key_share */ + bs_append_bytes(tls_extensions, (unsigned char []) { + 0x00, 0x33, // Extension: key_share (51) + 0x00, 0x26, // Extension Length (37) + 0x00, 0x24, // Key Share List Length (36) + 0x00, 0x1d, // Group ID (X25519) + 0x00, 0x20, // Key Exchange Length (32) + }, 10); + + /* Add 32 bytes of the (bogus) X25519 key share. */ + for (unsigned int j = 0; j < (32 / sizeof(uint32_t)); j++) + bs_append_uint32_t(tls_extensions, 0x029a029a); + + /* Add the supported_versions extension to signify we are using TLS v1.3. */ + tlsExtensionAddTLSv1_3(tls_extensions); + + /* Add the signature_algorithms extension. Only add the one group we are testing for. */ + bs_append_bytes(tls_extensions, (unsigned char []) { + 0x00, 0x0d, // Extension Type: signature_algorithms (13) + 0x00, 0x04, // Extension Length (4) + 0x00, 0x02, // Signature Hash Algorithms List Length (2) + }, 6); + bs_append_ushort(tls_extensions, sig_id); + + /* Update the TLS extensions length since we manually added to it. */ + bs_set_ushort(tls_extensions, 0, bs_get_len(tls_extensions) - 2); + + /* Create the Client Hello buffer using the ciphersuite list and TLS extensions. */ + client_hello = makeClientHello(options, 3, ciphersuite_list, tls_extensions); + + /* Free the TLS extensions since we're done with them. Note: we don't free the ciphersuite_list because we'll need them on the next loop. */ + bs_free(&tls_extensions); + + /* Now connect to the target server. */ + s = tcpConnect(options); + if (s == 0) { + ret = false; + goto done; + } + + /* Send the Client Hello message. */ + if (send(s, bs_get_bytes(client_hello), bs_get_len(client_hello), 0) <= 0) { + printf_error("send() failed while sending Client Hello: %d (%s)\n", errno, strerror(errno)); + ret = false; + goto done; + } + bs_free(&client_hello); + + server_hello = getServerHello(s); + CLOSE(s); + + /* This signature algorithm is not supported. */ + if (server_hello == NULL) + continue; + + bs_free(&server_hello); + + if (!printed_header) { + printf("\n %sServer Signature Algorithm(s):%s\n", COL_BLUE, RESET); + printed_header = 1; + } + + /* If the server accepted our bogus signature ID, then we can conclude that it will accept all of them (and not test any further). Some servers in the wild do this for some reason... */ + if (sig_id == BOGUS_SIG_ALG_ID) { + printf("%sServer accepts all signature algorithms.%s\n", COL_YELLOW, RESET); + goto done; + } else { + printf("%s%s%s\n", color, sig_name, RESET); + printf_xml(" \n", sig_name, sig_id); + } + } + + done: + CLOSE(s); + bs_free(&ciphersuite_list); + bs_free(&tls_extensions); + bs_free(&client_hello); + bs_free(&server_hello); + return ret; +} + /* MinGW doesn't have a memmem() implementation. */ #ifdef _WIN32 diff --git a/sslscan.h b/sslscan.h index 1517b99..b8c4d98 100644 --- a/sslscan.h +++ b/sslscan.h @@ -151,6 +151,7 @@ struct sslCheckOptions int compression; int heartbleed; int groups; + int signature_algorithms; int starttls_ftp; int starttls_imap; int starttls_irc; @@ -326,6 +327,7 @@ int testfallback(struct sslCheckOptions *, const SSL_METHOD *); #endif int testHeartbleed(struct sslCheckOptions *, const SSL_METHOD *); int testSupportedGroups(struct sslCheckOptions *options); +int testSignatureAlgorithms(struct sslCheckOptions *options); int testCipher(struct sslCheckOptions *, const SSL_METHOD *); int testMissingCiphers(struct sslCheckOptions *options, unsigned int version); int testProtocolCiphers(struct sslCheckOptions *, const SSL_METHOD *); From bac165aeb70eff82402c90971e67b453aba58da9 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Wed, 25 Dec 2019 20:20:24 -0500 Subject: [PATCH 41/52] Key exchange group enumeration now works in TLSv1.2. --- docker_test.sh | 39 +- docker_test/expected_output/test_1.txt | 16 +- docker_test/expected_output/test_10.txt | 6 +- docker_test/expected_output/test_11.txt | 8 + docker_test/expected_output/test_12.txt | 18 +- docker_test/expected_output/test_13.txt | 34 +- docker_test/expected_output/test_14.txt | 19 +- docker_test/expected_output/test_15.txt | 34 +- docker_test/expected_output/test_16.txt | 60 ++ docker_test/expected_output/test_17.txt | 51 ++ docker_test/expected_output/test_2.txt | 16 +- docker_test/expected_output/test_3.txt | 16 +- docker_test/expected_output/test_4.txt | 27 +- docker_test/expected_output/test_5.txt | 16 +- docker_test/expected_output/test_6.txt | 25 +- docker_test/expected_output/test_7.txt | 18 +- docker_test/expected_output/test_8.txt | 18 +- docker_test/expected_output/test_9.txt | 6 +- sslscan.c | 888 +++++++++++++++------- sslscan.h | 27 +- tools/iana_tls_supported_groups_parser.py | 126 +++ 21 files changed, 1070 insertions(+), 398 deletions(-) create mode 100644 docker_test/expected_output/test_16.txt create mode 100644 docker_test/expected_output/test_17.txt create mode 100755 tools/iana_tls_supported_groups_parser.py diff --git a/docker_test.sh b/docker_test.sh index 8273cd0..43f529b 100755 --- a/docker_test.sh +++ b/docker_test.sh @@ -40,6 +40,9 @@ REDB="\033[1;31m" # Red + bold YELLOWB="\033[1;33m" # Yellow + bold GREENB="\033[1;32m" # Green + bold +# Set to 0 if any test fails. +all_passed=1 + # Number of processors on this system (used to compile parallel builds). NUM_PROCS=`/usr/bin/nproc --all 2> /dev/null` @@ -270,6 +273,8 @@ function run_tests { run_test_13 "0" run_test_14 "0" run_test_15 "0" + run_test_16 "0" + run_test_17 "0" } @@ -335,7 +340,7 @@ function run_test_10 { # Makes an OCSP request to www.amazon.com. The horrible Perl command that comes after it will filter out the timestamps and other variable data from the response, otherwise the diff would fail. function run_test_11 { - run_test_internet '11' "./sslscan --ocsp --no-ciphersuites --no-fallback --no-renegotiation --no-compression --no-heartbleed --no-check-certificate www.amazon.com | perl -pe 'BEGIN{undef $/;} s/Connected to .+?$/Connected to\033[0m/smg; s/Responder Id: .+?$/Responder Id:/smg; s/Produced At: .+?$/Produced At:/smg; s/Hash Algorithm: .+?$/Hash Algorithm:/smg; s/Issuer Name Hash: .+?$/Issuer Name Hash:/smg; s/Issuer Key Hash: .+?$/Issuer Key Hash:/smg; s/Serial Number: .+?$/Serial Number:/smg; s/This Update: .+?$/This Update:/smg; s/Next Update: .+?$/Next Update:/smg; s/Response Single Extensions:.+?\n\n/\n\n/smg;'" + run_test_internet '11' "./sslscan --ocsp --no-ciphersuites --no-fallback --no-renegotiation --no-compression --no-heartbleed --no-check-certificate --no-groups --no-sigs www.amazon.com | perl -pe 'BEGIN{undef $/;} s/Connected to .+?$/Connected to\033[0m/smg; s/Responder Id: .+?$/Responder Id:/smg; s/Produced At: .+?$/Produced At:/smg; s/Hash Algorithm: .+?$/Hash Algorithm:/smg; s/Issuer Name Hash: .+?$/Issuer Name Hash:/smg; s/Issuer Key Hash: .+?$/Issuer Key Hash:/smg; s/Serial Number: .+?$/Serial Number:/smg; s/This Update: .+?$/This Update:/smg; s/Next Update: .+?$/Next Update:/smg; s/Response Single Extensions:.+?\n\n/\n\n/smg;'" } @@ -363,6 +368,18 @@ function run_test_15 { } +# OpenSSL v1.0.2, TLSv1.2 with sect163k1 curve only. +function run_test_16 { + run_test $1 '16' "/openssl_v1.0.2/openssl s_server -accept 443 -tls1_2 -named_curve sect163k1 -cert /etc/ssl/cert_1024.crt -key /etc/ssl/key_1024.pem" "" +} + + +# OpenSSL v1.1.1, TLSv1.2 with brainpoolP512r1 curve only. +function run_test_17 { + run_test $1 '17' "/openssl_v1.1.1/openssl s_server -accept 443 -tls1_2 -named_curve brainpoolP512r1 -cert /etc/ssl/cert_1024.crt -key /etc/ssl/key_1024.pem" "" +} + + # Run a test. Set the first argument to '1' to enable test debugging. # Second argument is the test number to run. Third argument is the executable and # its args to be run inside the container.. @@ -412,14 +429,16 @@ function run_test { if [[ ! -f ${expected_result_stdout} ]]; then test_result_stdout_actual=`cat ${test_result_stdout}` echo -e "\n${REDB}Error:${CLR} expected output file for test #${test_number} not found (${expected_result_stdout}). Actual test result is below. Manually verify that this output is correct; if so, then copy it to the expected test file path with:\n\n $ cp ${test_result_stdout} ${expected_result_stdout}\n\n------\n${test_result_stdout_actual}\n" - exit 1 + all_passed=0 + return fi # Compare the actual output to the expected output. Any discrepency results in test failure. diff=`diff -u ${expected_result_stdout} ${test_result_stdout}` if [[ $? != 0 ]]; then echo -e "Test #${test_number} ${REDB}FAILED${CLR}.\n\n${diff}\n" - exit 1 + all_passed=0 + return fi echo -e "Test #${test_number} ${GREEN}passed${CLR}." @@ -510,9 +529,11 @@ fi echo -e "\nRunning all tests..." run_tests -# The test functions above will terminate the script on failure, so if we reached here, -# all tests are successful. -echo -e "\n${GREENB}ALL TESTS PASS!${CLR}\n" - -rm -rf $TEST_RESULT_DIR -exit 0 +if [[ $all_passed == 1 ]]; then + echo -e "\n${GREENB}ALL TESTS PASS!${CLR}\n" + rm -rf $TEST_RESULT_DIR + exit 0 +else + echo -e "\n\n${YELLOWB}!! SOME TESTS FAILED !!${CLR}\n\n" + exit 1 +fi diff --git a/docker_test/expected_output/test_1.txt b/docker_test/expected_output/test_1.txt index 81b9db2..604667f 100644 --- a/docker_test/expected_output/test_1.txt +++ b/docker_test/expected_output/test_1.txt @@ -3,6 +3,14 @@ Testing SSL server localhost on port 4443 using SNI name localhost + SSL/TLS Protocols: +SSLv2 is not enabled +SSLv3 is enabled +TLSv1.0 is enabled +TLSv1.1 is enabled +TLSv1.2 is enabled +TLSv1.3 is not enabled + TLS Fallback SCSV: Server supports TLS Fallback SCSV @@ -13,15 +21,10 @@ Server supports TLS Fallback SCSV Compression enabled (CRIME) Heartbleed: -TLS 1.3 not vulnerable to heartbleed TLS 1.2 not vulnerable to heartbleed TLS 1.1 not vulnerable to heartbleed TLS 1.0 not vulnerable to heartbleed - SSL Protocols: -SSLv2 is not enabled -SSLv3 is enabled - Supported Server Cipher(s): Preferred TLSv1.2 256 bits ECDHE-RSA-AES256-GCM-SHA384  Curve P-256 DHE 256 Accepted TLSv1.2 256 bits DHE-RSA-AES256-GCM-SHA384  DHE 2048 bits @@ -92,6 +95,9 @@ Accepted TLSv1.0 128 bits RC4-SHA Accepted TLSv1.0 128 bits RC4-MD5  Accepted TLSv1.0 112 bits DES-CBC3-SHA  + Server Key Exchange Group(s): +TLSv1.2 128 bits secp256r1 (NIST P-256) + SSL Certificate: Signature Algorithm: sha256WithRSAEncryption RSA Key Strength: 2048 diff --git a/docker_test/expected_output/test_10.txt b/docker_test/expected_output/test_10.txt index 9140682..88dcec4 100644 --- a/docker_test/expected_output/test_10.txt +++ b/docker_test/expected_output/test_10.txt @@ -3,9 +3,13 @@ Testing SSL server localhost on port 4443 using SNI name localhost - SSL Protocols: + SSL/TLS Protocols: SSLv2 is not enabled SSLv3 is not enabled +TLSv1.0 is not enabled +TLSv1.1 is not enabled +TLSv1.2 is enabled +TLSv1.3 is not enabled Supported Server Cipher(s): Preferred 400 Bad Request TLSv1.2 256 bits ECDHE-RSA-CHACHA20-POLY1305  Curve 25519 DHE 253 diff --git a/docker_test/expected_output/test_11.txt b/docker_test/expected_output/test_11.txt index 6e2619a..f82112a 100644 --- a/docker_test/expected_output/test_11.txt +++ b/docker_test/expected_output/test_11.txt @@ -3,6 +3,14 @@ Testing SSL server www.amazon.com on port 443 using SNI name www.amazon.com + SSL/TLS Protocols: +SSLv2 is not enabled +SSLv3 is not enabled +TLSv1.0 is enabled +TLSv1.1 is enabled +TLSv1.2 is enabled +TLSv1.3 is not enabled + OCSP Stapling Request: OCSP Response Status: successful (0x0) Response Type: Basic OCSP Response diff --git a/docker_test/expected_output/test_12.txt b/docker_test/expected_output/test_12.txt index a1f93f7..c337873 100644 --- a/docker_test/expected_output/test_12.txt +++ b/docker_test/expected_output/test_12.txt @@ -3,6 +3,14 @@ Testing SSL server localhost on port 4443 using SNI name localhost + SSL/TLS Protocols: +SSLv2 is enabled +SSLv3 is enabled +TLSv1.0 is enabled +TLSv1.1 is not enabled +TLSv1.2 is not enabled +TLSv1.3 is not enabled + TLS Fallback SCSV: Server does not support TLS Fallback SCSV @@ -13,15 +21,8 @@ Server does not support TLS Fallback SCSV Compression enabled (CRIME) Heartbleed: -TLS 1.3 not vulnerable to heartbleed -TLS 1.2 not vulnerable to heartbleed -TLS 1.1 not vulnerable to heartbleed TLS 1.0 not vulnerable to heartbleed - SSL Protocols: -SSLv2 is enabled -SSLv3 is enabled - Supported Server Cipher(s): Preferred TLSv1.0 256 bits ECDHE-RSA-AES256-SHA Curve P-256 DHE 256 Accepted TLSv1.0 256 bits DHE-RSA-AES256-SHA DHE 512 bits @@ -45,6 +46,9 @@ Accepted TLSv1.0 112 bits DES-CBC3-SHA Accepted TLSv1.0 56 bits TLS_RSA_WITH_DES_CBC_SHA  Accepted TLSv1.0 56 bits TLS_DHE_RSA_WITH_DES_CBC_SHA  + Server Key Exchange Group(s): +TLSv1.0 128 bits secp256r1 (NIST P-256) + SSL Certificate: Signature Algorithm: md5WithRSAEncryption RSA Key Strength: 512 diff --git a/docker_test/expected_output/test_13.txt b/docker_test/expected_output/test_13.txt index 54523ca..51e5f24 100644 --- a/docker_test/expected_output/test_13.txt +++ b/docker_test/expected_output/test_13.txt @@ -3,6 +3,14 @@ Testing SSL server localhost on port 4443 using SNI name localhost + SSL/TLS Protocols: +SSLv2 is not enabled +SSLv3 is not enabled +TLSv1.0 is enabled +TLSv1.1 is enabled +TLSv1.2 is enabled +TLSv1.3 is enabled + TLS Fallback SCSV: Server supports TLS Fallback SCSV @@ -18,10 +26,6 @@ TLS 1.2 not vulnerable to heartbleed TLS 1.1 not vulnerable to heartbleed TLS 1.0 not vulnerable to heartbleed - SSL Protocols: -SSLv2 is not enabled -SSLv3 is not enabled - Supported Server Cipher(s): Preferred TLSv1.3 128 bits TLS_AES_128_GCM_SHA256 Curve 25519 DHE 253 Accepted TLSv1.3 256 bits TLS_AES_256_GCM_SHA384 Curve 25519 DHE 253 @@ -59,15 +63,19 @@ Accepted TLSv1.0 256 bits AES256-SHA Accepted TLSv1.0 128 bits AES128-SHA Server Key Exchange Group(s): -X25519 (128 bits) -secp256r1 [P-256] (128 bits) -secp384r1 [P-384] (192 bits) -secp521r1 [P-521] (256 bits) -ffdhe2048 (112 bits) -ffdhe3072 (128 bits) -ffdhe4096 (150 bits) -ffdhe6144 (175 bits) -ffdhe8192 (192 bits) +TLSv1.3 128 bits secp256r1 (NIST P-256) +TLSv1.3 192 bits secp384r1 (NIST P-384) +TLSv1.3 260 bits secp521r1 (NIST P-521) +TLSv1.3 128 bits x25519 +TLSv1.3 112 bits ffdhe2048 +TLSv1.3 128 bits ffdhe3072 +TLSv1.3 150 bits ffdhe4096 +TLSv1.3 175 bits ffdhe6144 +TLSv1.3 192 bits ffdhe8192 +TLSv1.2 128 bits secp256r1 (NIST P-256) +TLSv1.2 192 bits secp384r1 (NIST P-384) +TLSv1.2 260 bits secp521r1 (NIST P-521) +TLSv1.2 128 bits x25519 Server Signature Algorithm(s): rsa_pss_rsae_sha256 diff --git a/docker_test/expected_output/test_14.txt b/docker_test/expected_output/test_14.txt index 0ffa640..49d1a5f 100644 --- a/docker_test/expected_output/test_14.txt +++ b/docker_test/expected_output/test_14.txt @@ -3,6 +3,14 @@ Testing SSL server localhost on port 4443 using SNI name localhost + SSL/TLS Protocols: +SSLv2 is not enabled +SSLv3 is not enabled +TLSv1.0 is not enabled +TLSv1.1 is not enabled +TLSv1.2 is enabled +TLSv1.3 is enabled + TLS Fallback SCSV: Server supports TLS Fallback SCSV @@ -15,12 +23,6 @@ Compression disabled Heartbleed: TLS 1.3 not vulnerable to heartbleed TLS 1.2 not vulnerable to heartbleed -TLS 1.1 not vulnerable to heartbleed -TLS 1.0 not vulnerable to heartbleed - - SSL Protocols: -SSLv2 is not enabled -SSLv3 is not enabled Supported Server Cipher(s): Preferred TLSv1.3 128 bits TLS_AES_128_GCM_SHA256 Curve P-521 DHE 521 @@ -47,8 +49,9 @@ Accepted TLSv1.2 256 bits AES256-SHA Accepted TLSv1.2 128 bits AES128-SHA Server Key Exchange Group(s): -secp521r1 [P-521] (256 bits) -ffdhe8192 (192 bits) +TLSv1.3 260 bits secp521r1 (NIST P-521) +TLSv1.3 192 bits ffdhe8192 +TLSv1.2 260 bits secp521r1 (NIST P-521) Server Signature Algorithm(s): rsa_pss_rsae_sha256 diff --git a/docker_test/expected_output/test_15.txt b/docker_test/expected_output/test_15.txt index 1b0dd61..de33a1a 100644 --- a/docker_test/expected_output/test_15.txt +++ b/docker_test/expected_output/test_15.txt @@ -3,6 +3,14 @@ Testing SSL server localhost on port 4443 using SNI name localhost + SSL/TLS Protocols: +SSLv2 is not enabled +SSLv3 is not enabled +TLSv1.0 is enabled +TLSv1.1 is enabled +TLSv1.2 is enabled +TLSv1.3 is enabled + TLS Fallback SCSV: Server supports TLS Fallback SCSV @@ -18,10 +26,6 @@ TLS 1.2 not vulnerable to heartbleed TLS 1.1 not vulnerable to heartbleed TLS 1.0 not vulnerable to heartbleed - SSL Protocols: -SSLv2 is not enabled -SSLv3 is not enabled - Supported Server Cipher(s): Preferred TLSv1.3 128 bits TLS_AES_128_GCM_SHA256 Curve 25519 DHE 253 Accepted TLSv1.3 256 bits TLS_AES_256_GCM_SHA384 Curve 25519 DHE 253 @@ -40,15 +44,19 @@ Accepted TLSv1.1 128 bits ECDHE-ECDSA-AES128-SHA Curve 2 Accepted TLSv1.0 128 bits ECDHE-ECDSA-AES128-SHA Curve 25519 DHE 253 Server Key Exchange Group(s): -X25519 (128 bits) -secp256r1 [P-256] (128 bits) -secp384r1 [P-384] (192 bits) -secp521r1 [P-521] (256 bits) -ffdhe2048 (112 bits) -ffdhe3072 (128 bits) -ffdhe4096 (150 bits) -ffdhe6144 (175 bits) -ffdhe8192 (192 bits) +TLSv1.3 128 bits secp256r1 (NIST P-256) +TLSv1.3 192 bits secp384r1 (NIST P-384) +TLSv1.3 260 bits secp521r1 (NIST P-521) +TLSv1.3 128 bits x25519 +TLSv1.3 112 bits ffdhe2048 +TLSv1.3 128 bits ffdhe3072 +TLSv1.3 150 bits ffdhe4096 +TLSv1.3 175 bits ffdhe6144 +TLSv1.3 192 bits ffdhe8192 +TLSv1.2 128 bits secp256r1 (NIST P-256) +TLSv1.2 192 bits secp384r1 (NIST P-384) +TLSv1.2 260 bits secp521r1 (NIST P-521) +TLSv1.2 128 bits x25519 Server Signature Algorithm(s): ecdsa_secp256r1_sha256 diff --git a/docker_test/expected_output/test_16.txt b/docker_test/expected_output/test_16.txt new file mode 100644 index 0000000..55bac8a --- /dev/null +++ b/docker_test/expected_output/test_16.txt @@ -0,0 +1,60 @@ + +Connected to 127.0.0.1 + +Testing SSL server localhost on port 4443 using SNI name localhost + + SSL/TLS Protocols: +SSLv2 is not enabled +SSLv3 is not enabled +TLSv1.0 is not enabled +TLSv1.1 is not enabled +TLSv1.2 is enabled +TLSv1.3 is not enabled + + TLS Fallback SCSV: +Server supports TLS Fallback SCSV + + TLS renegotiation: +Session renegotiation not supported + + TLS Compression: +Compression disabled + + Heartbleed: +TLS 1.2 not vulnerable to heartbleed + + Supported Server Cipher(s): +Preferred TLSv1.2 256 bits DHE-RSA-AES256-GCM-SHA384  DHE 2048 bits +Accepted TLSv1.2 128 bits DHE-RSA-AES128-GCM-SHA256  DHE 2048 bits +Accepted TLSv1.2 256 bits DHE-RSA-AES256-SHA256 DHE 2048 bits +Accepted TLSv1.2 128 bits DHE-RSA-AES128-SHA256 DHE 2048 bits +Accepted TLSv1.2 256 bits DHE-RSA-AES256-SHA DHE 2048 bits +Accepted TLSv1.2 256 bits DHE-RSA-CAMELLIA256-SHA DHE 2048 bits +Accepted TLSv1.2 128 bits DHE-RSA-AES128-SHA DHE 2048 bits +Accepted TLSv1.2 128 bits DHE-RSA-SEED-SHA DHE 2048 bits +Accepted TLSv1.2 128 bits DHE-RSA-CAMELLIA128-SHA DHE 2048 bits +Accepted TLSv1.2 112 bits DHE-RSA-DES-CBC3-SHA  DHE 2048 bits +Accepted TLSv1.2 256 bits AES256-GCM-SHA384 +Accepted TLSv1.2 128 bits AES128-GCM-SHA256 +Accepted TLSv1.2 256 bits AES256-SHA256 +Accepted TLSv1.2 128 bits AES128-SHA256 +Accepted TLSv1.2 256 bits AES256-SHA +Accepted TLSv1.2 256 bits CAMELLIA256-SHA +Accepted TLSv1.2 128 bits AES128-SHA +Accepted TLSv1.2 128 bits SEED-SHA +Accepted TLSv1.2 128 bits CAMELLIA128-SHA +Accepted TLSv1.2 128 bits RC4-SHA  +Accepted TLSv1.2 128 bits RC4-MD5  +Accepted TLSv1.2 112 bits DES-CBC3-SHA  + + Server Key Exchange Group(s): +TLSv1.2 81 bits sect163k1 + + SSL Certificate: +Signature Algorithm: sha256WithRSAEncryption +RSA Key Strength: 1024 + +Subject: howfuckedismydatabase.com +Issuer: /C=XX/ST=Nowhere in particular/L=Nowhere +Not valid before: Dec 3 03:56:52 2019 GMT +Not valid after: Dec 3 03:56:52 2029 GMT diff --git a/docker_test/expected_output/test_17.txt b/docker_test/expected_output/test_17.txt new file mode 100644 index 0000000..c5302cb --- /dev/null +++ b/docker_test/expected_output/test_17.txt @@ -0,0 +1,51 @@ + +Connected to 127.0.0.1 + +Testing SSL server localhost on port 4443 using SNI name localhost + + SSL/TLS Protocols: +SSLv2 is not enabled +SSLv3 is not enabled +TLSv1.0 is not enabled +TLSv1.1 is not enabled +TLSv1.2 is enabled +TLSv1.3 is not enabled + + TLS Fallback SCSV: +Server supports TLS Fallback SCSV + + TLS renegotiation: +Session renegotiation not supported + + TLS Compression: +Compression disabled + + Heartbleed: +TLS 1.2 not vulnerable to heartbleed + + Supported Server Cipher(s): +Preferred TLSv1.2 256 bits DHE-RSA-AES256-GCM-SHA384  DHE 1024 bits +Accepted TLSv1.2 256 bits DHE-RSA-CHACHA20-POLY1305  DHE 1024 bits +Accepted TLSv1.2 128 bits DHE-RSA-AES128-GCM-SHA256  DHE 1024 bits +Accepted TLSv1.2 256 bits DHE-RSA-AES256-SHA256 DHE 1024 bits +Accepted TLSv1.2 128 bits DHE-RSA-AES128-SHA256 DHE 1024 bits +Accepted TLSv1.2 256 bits DHE-RSA-AES256-SHA DHE 1024 bits +Accepted TLSv1.2 128 bits DHE-RSA-AES128-SHA DHE 1024 bits +Accepted TLSv1.2 256 bits AES256-GCM-SHA384 +Accepted TLSv1.2 128 bits AES128-GCM-SHA256 +Accepted TLSv1.2 256 bits AES256-SHA256 +Accepted TLSv1.2 128 bits AES128-SHA256 +Accepted TLSv1.2 256 bits AES256-SHA +Accepted TLSv1.2 128 bits AES128-SHA + + Server Key Exchange Group(s): +TLSv1.2 256 bits brainpoolP512r1 + + SSL Certificate: +Signature Algorithm: sha256WithRSAEncryption +RSA Key Strength: 1024 + +Subject: howfuckedismydatabase.com +Issuer: /C=XX/ST=Nowhere in particular/L=Nowhere +Not valid before: Dec 3 03:56:52 2019 GMT +Not valid after: Dec 3 03:56:52 2029 GMT diff --git a/docker_test/expected_output/test_2.txt b/docker_test/expected_output/test_2.txt index d2814ca..4e2b891 100644 --- a/docker_test/expected_output/test_2.txt +++ b/docker_test/expected_output/test_2.txt @@ -3,6 +3,14 @@ Testing SSL server localhost on port 4443 using SNI name localhost + SSL/TLS Protocols: +SSLv2 is enabled +SSLv3 is not enabled +TLSv1.0 is not enabled +TLSv1.1 is not enabled +TLSv1.2 is not enabled +TLSv1.3 is not enabled + TLS Fallback SCSV: Connection failed - unable to determine TLS Fallback SCSV support @@ -13,14 +21,6 @@ Session renegotiation not supported Compression disabled Heartbleed: -TLS 1.3 not vulnerable to heartbleed -TLS 1.2 not vulnerable to heartbleed -TLS 1.1 not vulnerable to heartbleed -TLS 1.0 not vulnerable to heartbleed - - SSL Protocols: -SSLv2 is enabled -SSLv3 is not enabled Supported Server Cipher(s): Certificate information cannot be enumerated through SSLv2 nor SSLv3. diff --git a/docker_test/expected_output/test_3.txt b/docker_test/expected_output/test_3.txt index 94de8b9..aa5d0f5 100644 --- a/docker_test/expected_output/test_3.txt +++ b/docker_test/expected_output/test_3.txt @@ -3,6 +3,14 @@ Testing SSL server localhost on port 4443 using SNI name localhost + SSL/TLS Protocols: +SSLv2 is not enabled +SSLv3 is enabled +TLSv1.0 is not enabled +TLSv1.1 is not enabled +TLSv1.2 is not enabled +TLSv1.3 is not enabled + TLS Fallback SCSV: Connection failed - unable to determine TLS Fallback SCSV support @@ -13,14 +21,6 @@ Session renegotiation not supported Compression disabled Heartbleed: -TLS 1.3 not vulnerable to heartbleed -TLS 1.2 not vulnerable to heartbleed -TLS 1.1 not vulnerable to heartbleed -TLS 1.0 not vulnerable to heartbleed - - SSL Protocols: -SSLv2 is not enabled -SSLv3 is enabled Supported Server Cipher(s): Certificate information cannot be enumerated through SSLv2 nor SSLv3. diff --git a/docker_test/expected_output/test_4.txt b/docker_test/expected_output/test_4.txt index 21c0d45..010f1f2 100644 --- a/docker_test/expected_output/test_4.txt +++ b/docker_test/expected_output/test_4.txt @@ -3,6 +3,14 @@ Testing SSL server localhost on port 4443 using SNI name localhost + SSL/TLS Protocols: +SSLv2 is not enabled +SSLv3 is not enabled +TLSv1.0 is enabled +TLSv1.1 is enabled +TLSv1.2 is enabled +TLSv1.3 is enabled + TLS Fallback SCSV: Server supports TLS Fallback SCSV @@ -18,10 +26,6 @@ TLS 1.2 not vulnerable to heartbleed TLS 1.1 not vulnerable to heartbleed TLS 1.0 not vulnerable to heartbleed - SSL Protocols: -SSLv2 is not enabled -SSLv3 is not enabled - Supported Server Cipher(s): Preferred TLSv1.3 128 bits TLS_AES_128_GCM_SHA256 Curve 25519 DHE 253 Accepted TLSv1.3 256 bits TLS_AES_256_GCM_SHA384 Curve 25519 DHE 253 @@ -60,11 +64,16 @@ Accepted TLSv1.0 256 bits AES256-SHA Accepted TLSv1.0 128 bits AES128-SHA Server Key Exchange Group(s): -X25519 (128 bits) -X448 (224 bits) -secp256r1 [P-256] (128 bits) -secp384r1 [P-384] (192 bits) -secp521r1 [P-521] (256 bits) +TLSv1.3 128 bits secp256r1 (NIST P-256) +TLSv1.3 192 bits secp384r1 (NIST P-384) +TLSv1.3 260 bits secp521r1 (NIST P-521) +TLSv1.3 128 bits x25519 +TLSv1.3 224 bits x448 +TLSv1.2 128 bits secp256r1 (NIST P-256) +TLSv1.2 192 bits secp384r1 (NIST P-384) +TLSv1.2 260 bits secp521r1 (NIST P-521) +TLSv1.2 128 bits x25519 +TLSv1.2 224 bits x448 Server Signature Algorithm(s): rsa_pss_rsae_sha256 diff --git a/docker_test/expected_output/test_5.txt b/docker_test/expected_output/test_5.txt index 1c54738..686cc12 100644 --- a/docker_test/expected_output/test_5.txt +++ b/docker_test/expected_output/test_5.txt @@ -3,6 +3,14 @@ Testing SSL server localhost on port 4443 using SNI name localhost + SSL/TLS Protocols: +SSLv2 is not enabled +SSLv3 is enabled +TLSv1.0 is enabled +TLSv1.1 is enabled +TLSv1.2 is enabled +TLSv1.3 is not enabled + TLS Fallback SCSV: Server supports TLS Fallback SCSV @@ -13,15 +21,10 @@ Server supports TLS Fallback SCSV Compression enabled (CRIME) Heartbleed: -TLS 1.3 not vulnerable to heartbleed TLS 1.2 not vulnerable to heartbleed TLS 1.1 not vulnerable to heartbleed TLS 1.0 not vulnerable to heartbleed - SSL Protocols: -SSLv2 is not enabled -SSLv3 is enabled - Supported Server Cipher(s): Preferred TLSv1.2 256 bits ECDHE-RSA-AES256-GCM-SHA384  Curve P-256 DHE 256 Accepted TLSv1.2 256 bits DHE-RSA-AES256-GCM-SHA384  DHE 1024 bits @@ -147,6 +150,9 @@ Accepted TLSv1.0 56 bits TLS_RSA_WITH_DES_CBC_SHA Accepted TLSv1.0 56 bits TLS_DHE_RSA_WITH_DES_CBC_SHA  Accepted TLSv1.0 56 bits TLS_DH_anon_WITH_DES_CBC_SHA  + Server Key Exchange Group(s): +TLSv1.2 128 bits secp256r1 (NIST P-256) + SSL Certificate: Signature Algorithm: sha256WithRSAEncryption RSA Key Strength: 1024 diff --git a/docker_test/expected_output/test_6.txt b/docker_test/expected_output/test_6.txt index 9aec781..4e52bc1 100644 --- a/docker_test/expected_output/test_6.txt +++ b/docker_test/expected_output/test_6.txt @@ -3,6 +3,14 @@ Testing SSL server localhost on port 4443 using SNI name localhost + SSL/TLS Protocols: +SSLv2 is not enabled +SSLv3 is not enabled +TLSv1.0 is not enabled +TLSv1.1 is not enabled +TLSv1.2 is not enabled +TLSv1.3 is enabled + TLS Fallback SCSV: Server supports TLS Fallback SCSV @@ -14,13 +22,6 @@ Compression disabled Heartbleed: TLS 1.3 not vulnerable to heartbleed -TLS 1.2 not vulnerable to heartbleed -TLS 1.1 not vulnerable to heartbleed -TLS 1.0 not vulnerable to heartbleed - - SSL Protocols: -SSLv2 is not enabled -SSLv3 is not enabled Supported Server Cipher(s): Preferred TLSv1.3 128 bits TLS_AES_128_GCM_SHA256 Curve 25519 DHE 253 @@ -30,11 +31,11 @@ Accepted TLSv1.3 128 bits TLS_AES_128_CCM_SHA256 Curve 2 Accepted TLSv1.3 128 bits TLS_AES_128_CCM_8_SHA256 Curve 25519 DHE 253 Server Key Exchange Group(s): -X25519 (128 bits) -X448 (224 bits) -secp256r1 [P-256] (128 bits) -secp384r1 [P-384] (192 bits) -secp521r1 [P-521] (256 bits) +TLSv1.3 128 bits secp256r1 (NIST P-256) +TLSv1.3 192 bits secp384r1 (NIST P-384) +TLSv1.3 260 bits secp521r1 (NIST P-521) +TLSv1.3 128 bits x25519 +TLSv1.3 224 bits x448 Server Signature Algorithm(s): rsa_pss_rsae_sha256 diff --git a/docker_test/expected_output/test_7.txt b/docker_test/expected_output/test_7.txt index d1101e7..5fb44bc 100644 --- a/docker_test/expected_output/test_7.txt +++ b/docker_test/expected_output/test_7.txt @@ -3,6 +3,14 @@ Testing SSL server localhost on port 4443 using SNI name localhost + SSL/TLS Protocols: +SSLv2 is enabled +SSLv3 is enabled +TLSv1.0 is enabled +TLSv1.1 is not enabled +TLSv1.2 is not enabled +TLSv1.3 is not enabled + TLS Fallback SCSV: Server does not support TLS Fallback SCSV @@ -13,15 +21,8 @@ Server does not support TLS Fallback SCSV Compression enabled (CRIME) Heartbleed: -TLS 1.3 not vulnerable to heartbleed -TLS 1.2 not vulnerable to heartbleed -TLS 1.1 not vulnerable to heartbleed TLS 1.0 not vulnerable to heartbleed - SSL Protocols: -SSLv2 is enabled -SSLv3 is enabled - Supported Server Cipher(s): Preferred TLSv1.0 256 bits ECDHE-RSA-AES256-SHA Curve P-256 DHE 256 Accepted TLSv1.0 256 bits DHE-RSA-AES256-SHA DHE 512 bits @@ -45,6 +46,9 @@ Accepted TLSv1.0 112 bits DES-CBC3-SHA Accepted TLSv1.0 56 bits TLS_RSA_WITH_DES_CBC_SHA  Accepted TLSv1.0 56 bits TLS_DHE_RSA_WITH_DES_CBC_SHA  + Server Key Exchange Group(s): +TLSv1.0 128 bits secp256r1 (NIST P-256) + SSL Certificate: Signature Algorithm: sha256WithRSAEncryption RSA Key Strength: 3072 diff --git a/docker_test/expected_output/test_8.txt b/docker_test/expected_output/test_8.txt index 712ffda..60cf251 100644 --- a/docker_test/expected_output/test_8.txt +++ b/docker_test/expected_output/test_8.txt @@ -3,6 +3,14 @@ Testing SSL server localhost on port 4443 using SNI name localhost + SSL/TLS Protocols: +SSLv2 is enabled +SSLv3 is enabled +TLSv1.0 is enabled +TLSv1.1 is not enabled +TLSv1.2 is not enabled +TLSv1.3 is not enabled + TLS Fallback SCSV: Server does not support TLS Fallback SCSV @@ -13,15 +21,8 @@ Server does not support TLS Fallback SCSV Compression enabled (CRIME) Heartbleed: -TLS 1.3 not vulnerable to heartbleed -TLS 1.2 not vulnerable to heartbleed -TLS 1.1 not vulnerable to heartbleed TLS 1.0 not vulnerable to heartbleed - SSL Protocols: -SSLv2 is enabled -SSLv3 is enabled - Supported Server Cipher(s): Preferred TLSv1.0 256 bits ECDHE-RSA-AES256-SHA Curve P-256 DHE 256 Accepted TLSv1.0 256 bits DHE-RSA-AES256-SHA DHE 512 bits @@ -67,6 +68,9 @@ Accepted TLSv1.0 40 bits TLS_DH_anon_EXPORT_WITH_RC4_ Accepted TLSv1.0 40 bits TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA Accepted TLSv1.0 56 bits TLS_DH_anon_WITH_DES_CBC_SHA  + Server Key Exchange Group(s): +TLSv1.0 128 bits secp256r1 (NIST P-256) + SSL Certificate: Signature Algorithm: sha256WithRSAEncryption RSA Key Strength: 3072 diff --git a/docker_test/expected_output/test_9.txt b/docker_test/expected_output/test_9.txt index b1800f0..0a10aa2 100644 --- a/docker_test/expected_output/test_9.txt +++ b/docker_test/expected_output/test_9.txt @@ -3,9 +3,13 @@ Testing SSL server localhost on port 4443 using SNI name localhost - SSL Protocols: + SSL/TLS Protocols: SSLv2 is not enabled SSLv3 is not enabled +TLSv1.0 is not enabled +TLSv1.1 is not enabled +TLSv1.2 is enabled +TLSv1.3 is not enabled Supported Server Cipher(s): Preferred 200 OK TLSv1.2 256 bits ECDHE-RSA-CHACHA20-POLY1305  Curve 25519 DHE 253 diff --git a/sslscan.c b/sslscan.c index 8c11d65..63f74f9 100644 --- a/sslscan.c +++ b/sslscan.c @@ -3298,13 +3298,13 @@ int testProtocolCiphers(struct sslCheckOptions *options, const SSL_METHOD *sslMe /* Test the missing ciphersuites. */ if (sslMethod != TLSv1_3_client_method()) { - int version = 0; + int tls_version = TLSv1_0; if (sslMethod == TLSv1_1_client_method()) - version = 1; + tls_version = TLSv1_1; else if (sslMethod == TLSv1_2_client_method()) - version = 2; + tls_version = TLSv1_2; - testMissingCiphers(options, version); + testMissingCiphers(options, tls_version); } return true; } @@ -3328,6 +3328,72 @@ int testHost(struct sslCheckOptions *options) printf("Testing SSL server %s%s%s on port %s%d%s using SNI name %s%s%s\n\n", COL_GREEN, options->host, RESET, COL_GREEN, options->port, RESET, COL_GREEN, options->sniname, RESET); + printf(" %sSSL/TLS Protocols:%s\n", COL_BLUE, RESET); + + // Check if SSLv2 is enabled. + if ((options->sslVersion == ssl_all) || (options->sslVersion == ssl_v2)) { + if (runSSLv2Test(options)) { + printf("SSLv2 is %senabled%s\n", COL_RED, RESET); + printf_xml(" \n"); + } else { + printf("SSLv2 is %snot enabled%s\n", COL_GREEN, RESET); + printf_xml(" \n"); + } + } + + // Check if SSLv3 is enabled. + if ((options->sslVersion == ssl_all) || (options->sslVersion == ssl_v3)) { + if (runSSLv3Test(options)) { + printf("SSLv3 is %senabled%s\n", COL_RED, RESET); + printf_xml(" \n"); + } else { + printf("SSLv3 is %snot enabled%s\n", COL_GREEN, RESET); + printf_xml(" \n"); + } + } + + /* Test if TLSv1.0 through TLSv1.3 is supported. This allows us to skip unnecessary tests later. Print status of each protocol when verbose flag is set. */ + if ((options->sslVersion == ssl_all) || (options->sslVersion == tls_all) || (options->sslVersion == tls_v10)) { + if ((options->tls10_supported = checkIfTLSVersionIsSupported(options, TLSv1_0))) { + printf("TLSv1.0 is %senabled%s\n", COL_YELLOW, RESET); + printf_xml(" \n"); + } else { + printf("TLSv1.0 is %snot enabled%s\n", COL_GREEN, RESET); + printf_xml(" \n"); + } + } + + if ((options->sslVersion == ssl_all) || (options->sslVersion == tls_all) || (options->sslVersion == tls_v11)) { + if ((options->tls11_supported = checkIfTLSVersionIsSupported(options, TLSv1_1))) { + printf("TLSv1.1 is enabled\n"); + printf_xml(" \n"); + } else { + printf("TLSv1.1 is not enabled\n"); + printf_xml(" \n"); + } + } + + if ((options->sslVersion == ssl_all) || (options->sslVersion == tls_all) || (options->sslVersion == tls_v12)) { + if ((options->tls12_supported = checkIfTLSVersionIsSupported(options, TLSv1_2))) { + printf("TLSv1.2 is enabled\n"); + printf_xml(" \n"); + } else { + printf("TLSv1.2 is not enabled\n"); + printf_xml(" \n"); + } + } + + if ((options->sslVersion == ssl_all) || (options->sslVersion == tls_all) || (options->sslVersion == tls_v13)) { + if ((options->tls13_supported = checkIfTLSVersionIsSupported(options, TLSv1_3))) { + printf("TLSv1.3 is enabled\n"); + printf_xml(" \n"); + } else { + printf("TLSv1.3 is not enabled\n"); + printf_xml(" \n"); + } + } + printf("\n"); + if (options->showClientCiphers == true) { // Build a list of ciphers... @@ -3406,23 +3472,23 @@ int testHost(struct sslCheckOptions *options) { printf(" %sHeartbleed:%s\n", COL_BLUE, RESET); #if OPENSSL_VERSION_NUMBER >= 0x10001000L - if( options->sslVersion == ssl_all || options->sslVersion == tls_all || options->sslVersion == tls_v13) + if ((options->sslVersion == ssl_all || options->sslVersion == tls_all || options->sslVersion == tls_v13) && options->tls13_supported) { printf("TLS 1.3 "); status = testHeartbleed(options, TLSv1_3_client_method()); } - if( options->sslVersion == ssl_all || options->sslVersion == tls_all || options->sslVersion == tls_v12) + if ((options->sslVersion == ssl_all || options->sslVersion == tls_all || options->sslVersion == tls_v12) && options->tls12_supported) { printf("TLS 1.2 "); status = testHeartbleed(options, TLSv1_2_client_method()); } - if( options->sslVersion == ssl_all || options->sslVersion == tls_all || options->sslVersion == tls_v11) + if ((options->sslVersion == ssl_all || options->sslVersion == tls_all || options->sslVersion == tls_v11) && options->tls11_supported) { printf("TLS 1.1 "); status = testHeartbleed(options, TLSv1_1_client_method()); } #endif - if( options->sslVersion == ssl_all || options->sslVersion == tls_all || options->sslVersion == tls_v10) + if ((options->sslVersion == ssl_all || options->sslVersion == tls_all || options->sslVersion == tls_v10) && options->tls10_supported) { printf("TLS 1.0 "); status = testHeartbleed(options, TLSv1_client_method()); @@ -3445,73 +3511,37 @@ int testHost(struct sslCheckOptions *options) if (options->ciphersuites) { - printf(" %sSSL Protocols:%s\n", COL_BLUE, RESET); - - // Check if SSLv2 is enabled. - if ((options->sslVersion == ssl_all) || (options->sslVersion == ssl_v2)) { - if (runSSLv2Test(options)) { - printf("SSLv2 is %senabled%s\n", COL_RED, RESET); - printf_xml(" \n"); - } else { - printf("SSLv2 is %snot enabled%s\n", COL_GREEN, RESET); - printf_xml(" \n"); - } - } - - // Check if SSLv3 is enabled. - if ((options->sslVersion == ssl_all) || (options->sslVersion == ssl_v3)) { - if (runSSLv3Test(options)) { - printf("SSLv3 is %senabled%s\n", COL_RED, RESET); - printf_xml(" \n"); - } else { - printf("SSLv3 is %snot enabled%s\n", COL_GREEN, RESET); - printf_xml(" \n"); - } - } - printf("\n"); - // Test supported ciphers... printf(" %sSupported Server Cipher(s):%s\n", COL_BLUE, RESET); switch (options->sslVersion) { case ssl_all: - if (status != false) - status = testProtocolCiphers(options, TLSv1_3_client_method()); -#if OPENSSL_VERSION_NUMBER >= 0x10001000L - if (status != false) - status = testProtocolCiphers(options, TLSv1_2_client_method()); - if (status != false) - status = testProtocolCiphers(options, TLSv1_1_client_method()); -#endif - if (status != false) - status = testProtocolCiphers(options, TLSv1_client_method()); - break; case tls_all: - if (status != false) + if ((status != false) && options->tls13_supported) status = testProtocolCiphers(options, TLSv1_3_client_method()); -#if OPENSSL_VERSION_NUMBER >= 0x10001000L - if (status != false) + if ((status != false) && options->tls12_supported) status = testProtocolCiphers(options, TLSv1_2_client_method()); - if (status != false) + if ((status != false) && options->tls11_supported) status = testProtocolCiphers(options, TLSv1_1_client_method()); -#endif - if (status != false) + if ((status != false) && options->tls10_supported) status = testProtocolCiphers(options, TLSv1_client_method()); break; case tls_v10: - status = testProtocolCiphers(options, TLSv1_client_method()); + if ((status != false) && options->tls10_supported) + status = testProtocolCiphers(options, TLSv1_client_method()); break; -#if OPENSSL_VERSION_NUMBER >= 0x10001000L case tls_v11: - status = testProtocolCiphers(options, TLSv1_1_client_method()); + if ((status != false) && options->tls11_supported) + status = testProtocolCiphers(options, TLSv1_1_client_method()); break; case tls_v12: - status = testProtocolCiphers(options, TLSv1_2_client_method()); + if ((status != false) && options->tls12_supported) + status = testProtocolCiphers(options, TLSv1_2_client_method()); break; case tls_v13: - status = testProtocolCiphers(options, TLSv1_3_client_method()); + if ((status != false) && options->tls13_supported) + status = testProtocolCiphers(options, TLSv1_3_client_method()); break; -#endif } } @@ -3520,7 +3550,7 @@ int testHost(struct sslCheckOptions *options) testSupportedGroups(options); // Enumerate signature algorithms. - if (options->signature_algorithms) + if (options->signature_algorithms && options->tls13_supported) testSignatureAlgorithms(options); // Print certificate @@ -4206,7 +4236,7 @@ int main(int argc, char *argv[]) } int runSSLv2Test(struct sslCheckOptions *options) { - int ret = false, s = 0; + int ret = false, s = -1; char sslv2_client_hello[] = { 0x80, 0x34, /* Length: 52 */ @@ -4256,7 +4286,7 @@ int runSSLv2Test(struct sslCheckOptions *options) { } int runSSLv3Test(struct sslCheckOptions *options) { - int ret = false, s = 0; + int ret = false, s = -1; uint32_t timestamp = 0; unsigned char timestamp_bytes[4] = {0}; char sslv3_client_hello_1[] = { @@ -4651,42 +4681,184 @@ int bs_read_socket(bs *b, int s, size_t num_bytes) { return ret; } -/* Returns a byte string, ciphersuite_list, with a list of ciphersuites for a given TLS version. When 'type' is CIPHERSUITES_MISSING, then a list of all ciphersuites missing in OpenSSL is returned. When set to CIPHERSUITES_TLSV1_3_ALL, all TLSv1.3 ciphersuites are returned only. */ -#define CIPHERSUITES_MISSING 0 -#define CIPHERSUITES_TLSV1_3_ALL 1 -bs *makeCiphersuiteList(unsigned int tls_version, unsigned int type) { - size_t ciphersuite_list_size = 1024; + +/* Returns true if a specific TLS version is supported by the server. */ +unsigned int checkIfTLSVersionIsSupported(struct sslCheckOptions *options, unsigned int tls_version) { + bs *tls_extensions = NULL, *ciphersuite_list = NULL, *client_hello = NULL, *server_hello = NULL; + int ret = false, s = -1; + unsigned int include_server_signatures = 0; + + + if (tls_version == TLSv1_3) + include_server_signatures = 1; + + tls_extensions = makeTLSExtensions(options, include_server_signatures); + if (tls_version == TLSv1_2) { + /* Extension: supported_groups */ + bs_append_bytes(tls_extensions, (unsigned char []) { + 0x00, 0x0a, // Extension: supported_groups (10) + 0x00, 0x1c, // Extension Length (28) + 0x00, 0x1a, // Supported Groups List Length (26) + 0x00, 0x17, // secp256r1 + 0x00, 0x19, // secp521r1 + 0x00, 0x1c, // brainpoolP512r1 + 0x00, 0x1b, // brainpoolP384r1 + 0x00, 0x18, // secp384r1 + 0x00, 0x1a, // brainpoolP256r1 + 0x00, 0x16, // secp256k1 + 0x00, 0x0e, // sect571r1 + 0x00, 0x0d, // sect571k1 + 0x00, 0x0b, // sect409k1 + 0x00, 0x0c, // sect409r1 + 0x00, 0x09, // sect283k1 + 0x00, 0x0a, // sect283r1 + }, 32); + + /* Update the length of the extensions. */ + tlsExtensionUpdateLength(tls_extensions); + } else if (tls_version == TLSv1_3) { + /* Extension: supported_groups */ + bs_append_bytes(tls_extensions, (unsigned char []) { + 0x00, 0x0a, // Extension: supported_groups (10) + 0x00, 0x16, // Extension Length (22) + 0x00, 0x14, // Supported Groups List Length (20) + 0x00, 0x17, // secp256r1 + 0x00, 0x19, // secp521r1 + 0x00, 0x18, // secp384r1 + 0x00, 0x1d, // X25519 + 0x00, 0x1e, // X448 + 0x01, 0x00, // FFDHE2048 + 0x01, 0x01, // FFDHE3072 + 0x01, 0x02, // FFDHE4096 + 0x01, 0x03, // FFDHE6144 + 0x01, 0x04, // FFDHE8192 + }, 26); + + /* Add key share for X25519. */ + tlsExtensionAddDefaultKeyShare(tls_extensions); + + /* Explicitly mark that this is a TLSv1.3 Client Hello. */ + tlsExtensionAddTLSv1_3(tls_extensions); + + /* Update the length of the extensions. */ + tlsExtensionUpdateLength(tls_extensions); + } + + ciphersuite_list = makeCiphersuiteListAll(tls_version); + client_hello = makeClientHello(options, tls_version, ciphersuite_list, tls_extensions); + bs_free(&ciphersuite_list); + bs_free(&tls_extensions); + + /* Now connect to the target server. */ + s = tcpConnect(options); + if (s == 0) + goto done; + + /* Send the Client Hello message. */ + if (send(s, bs_get_bytes(client_hello), bs_get_len(client_hello), 0) <= 0) { + printf_error("send() failed while sending Client Hello: %d (%s)\n", errno, strerror(errno)); + goto done; /* Returns false. */ + } + bs_free(&client_hello); + + server_hello = getServerHello(s); + + /* If we don't receive a proper Server Hello message, then this TLS version is not supported. */ + if (server_hello == NULL) + goto done; + + unsigned int expected_tls_version_low = tls_version + 1; + if (tls_version == TLSv1_3) + expected_tls_version_low = 3; + + /* Get the server's TLS version and compare it with what we sent. */ + unsigned int server_tls_version_high = bs_get_byte(server_hello, 9); + unsigned int server_tls_version_low = bs_get_byte(server_hello, 10); + if ((server_tls_version_high != 3) || (server_tls_version_low != expected_tls_version_low)) + goto done; + + /* A valid Server Hello was returned, so this TLS version is supported. */ + ret = true; + + done: + CLOSE(s); + bs_free(&ciphersuite_list); + bs_free(&tls_extensions); + bs_free(&client_hello); + bs_free(&server_hello); + return ret; +} + +/* Given a TLSv1_? constant, return its printable string representation. */ +char *getPrintableTLSName(unsigned int tls_version) { + switch (tls_version) { + case TLSv1_0: + return "TLSv1.0"; + case TLSv1_1: + return "TLSv1.1"; + case TLSv1_2: + return "TLSv1.2"; + case TLSv1_3: + return "TLSv1.3"; + default: + return "Unknown"; + } +} + +/* Returns a byte string of all TLSv1.3 cipher suites. The caller must eventually call bs_free() on it. */ +bs *makeCiphersuiteListTLS13All() { bs *ciphersuite_list = NULL; + bs_new_size(&ciphersuite_list, 16); + bs_append_bytes(ciphersuite_list, (unsigned char []) { + 0x13, 0x01, // TLS_AES_128_GCM_SHA256 + 0x13, 0x02, // TLS_AES_256_GCM_SHA384 + 0x13, 0x03, // TLS_CHACHA20_POLY1305_SHA256 + 0x13, 0x04, // TLS_AES_128_CCM_SHA256 + 0x13, 0x05, // TLS_AES_128_CCM_8_SHA256 + }, 10); - // Make the buffer much smaller if we're just returning the list of 5 TLSv1.3 ciphers. - if (type == CIPHERSUITES_TLSV1_3_ALL) - ciphersuite_list_size = 16; + return ciphersuite_list; +} - bs_new_size(&ciphersuite_list, ciphersuite_list_size); - if (type == CIPHERSUITES_MISSING) { - if (tls_version == 0) - tls_version = V1_0; - else if (tls_version == 1) - tls_version = V1_1; - else if (tls_version == 2) - tls_version = V1_2; +/* Returns a byte string with a list of all ciphersuites registered by IANA. */ +bs *makeCiphersuiteListAll(unsigned int tls_version) { + bs *ciphersuite_list = NULL; - for (int i = 0; i < (sizeof(missing_ciphersuites) / sizeof(struct missing_ciphersuite)); i++) { - /* Append only those that OpenSSL does not cover, and those that were not already accepted through a previous run. */ - if ((missing_ciphersuites[i].check_tls_versions & tls_version) && ((missing_ciphersuites[i].accepted_tls_versions & tls_version) == 0)) { - bs_append_ushort(ciphersuite_list, missing_ciphersuites[i].id); - } + /* If its TLSv1.3, return the smaller v1.3-specific list. */ + if (tls_version == TLSv1_3) + return makeCiphersuiteListTLS13All(); + + bs_new_size(&ciphersuite_list, 1024); + + for (int i = 0; i < (sizeof(missing_ciphersuites) / sizeof(struct missing_ciphersuite)); i++) { + if (!strstr(missing_ciphersuites[i].protocol_name, "PRIVATE_CIPHER_")) + bs_append_ushort(ciphersuite_list, missing_ciphersuites[i].id); + } + + return ciphersuite_list; +} + + +/* Returns a byte string with a list of all missing ciphersuites for a given TLS version (TLSv1_? constant) .*/ +bs *makeCiphersuiteListMissing(unsigned int tls_version) { + bs *ciphersuite_list = NULL; + + bs_new_size(&ciphersuite_list, 1024); + + if (tls_version == TLSv1_0) + tls_version = V1_0; + else if (tls_version == TLSv1_1) + tls_version = V1_1; + else if (tls_version == TLSv1_2) + tls_version = V1_2; + + for (int i = 0; i < (sizeof(missing_ciphersuites) / sizeof(struct missing_ciphersuite)); i++) { + /* Append only those that OpenSSL does not cover, and those that were not already accepted through a previous run. */ + if ((missing_ciphersuites[i].check_tls_versions & tls_version) && ((missing_ciphersuites[i].accepted_tls_versions & tls_version) == 0)) { + bs_append_ushort(ciphersuite_list, missing_ciphersuites[i].id); } - } else if (type == CIPHERSUITES_TLSV1_3_ALL) { - bs_append_bytes(ciphersuite_list, (unsigned char []) { - 0x13, 0x01, // TLS_AES_128_GCM_SHA256 - 0x13, 0x02, // TLS_AES_256_GCM_SHA384 - 0x13, 0x03, // TLS_CHACHA20_POLY1305_SHA256 - 0x13, 0x04, // TLS_AES_128_CCM_SHA256 - 0x13, 0x05, // TLS_AES_128_CCM_8_SHA256 - }, 10); } return ciphersuite_list; @@ -4694,11 +4866,11 @@ bs *makeCiphersuiteList(unsigned int tls_version, unsigned int type) { /* Marks a ciphersuite as found so that it is not re-tested again. */ void markFoundCiphersuite(unsigned short server_cipher_id, unsigned int tls_version) { - if (tls_version == 0) + if (tls_version == TLSv1_0) tls_version = V1_0; - else if (tls_version == 1) + else if (tls_version == TLSv1_1) tls_version = V1_1; - else if (tls_version == 2) + else if (tls_version == TLSv1_2) tls_version = V1_2; for (int i = 0; i < (sizeof(missing_ciphersuites) / sizeof(struct missing_ciphersuite)); i++) { @@ -4762,27 +4934,36 @@ bs *makeTLSExtensions(struct sslCheckOptions *options, unsigned int include_sign /* Extension: signature_algorithms */ bs_append_bytes(tls_extensions, (unsigned char []) { 0x00, 0x0d, // Extension: signature_algorithms (13) - 0x00, 0x1e, // Extension Length (30) - 0x00, 0x1c, // Signature Hash Algorithms Length (28) - 0x04, 0x03, // ecdsa_secp256r1_sha256 - 0x05, 0x03, // ecdsa_secp384r1_sha384 - 0x06, 0x03, // ecdsa_secp521r1_sha512 + 0x00, 0x30, // Extension Length (48) + 0x00, 0x2e, // Signature Hash Algorithms Length (46) + 0x08, 0x04, // rsa_pss_rsae_sha256 + 0x08, 0x05, // rsa_pss_rsae_sha384 + 0x08, 0x06, // rsa_pss_rsae_sha512 0x08, 0x07, // ed25519 0x08, 0x08, // ed448 0x08, 0x09, // rsa_pss_pss_sha256 0x08, 0x0a, // rsa_pss_pss_sha384 0x08, 0x0b, // rsa_pss_pss_sha512 - 0x08, 0x04, // rsa_pss_rsae_sha256 - 0x08, 0x05, // rsa_pss_rsae_sha384 - 0x08, 0x06, // rsa_pss_rsae_sha512 - 0x04, 0x01, // rsa_pkcs1_sha256 - 0x05, 0x01, // rsa_pkcs1_sha384 0x06, 0x01, // rsa_pkcs1_sha512 - }, 34); + 0x06, 0x02, // SHA512 DSA + 0x06, 0x03, // ecdsa_secp521r1_sha512 + 0x05, 0x01, // rsa_pkcs1_sha384 + 0x05, 0x02, // SHA384 DSA + 0x05, 0x03, // ecdsa_secp384r1_sha384 + 0x04, 0x01, // rsa_pkcs1_sha256" + 0x04, 0x02, // SHA256 DSA + 0x04, 0x03, // ecdsa_secp256r1_sha256 + 0x03, 0x01, // SHA224 ECDSA + 0x03, 0x02, // SHA224 DSA + 0x03, 0x03, // SHA224 ECDSA + 0x02, 0x01, // rsa_pkcs1_sha1 + 0x02, 0x02, // SHA1 DSA + 0x02, 0x03, // ecdsa_sha1 + }, 52); } /* Set the extension length. */ - bs_set_ushort(tls_extensions, 0, bs_get_len(tls_extensions) - 2); + tlsExtensionUpdateLength(tls_extensions); return tls_extensions; } @@ -4794,31 +4975,72 @@ void tlsExtensionAddTLSv1_3(bs *tls_extensions) { 0x02, // Supported Versions Length 0x03, 0x04, // Supported Version: TLS v1.3 }, 7); - bs_set_ushort(tls_extensions, 0, bs_get_len(tls_extensions) - 2); + tlsExtensionUpdateLength(tls_extensions); } -/* From socket s, reads a ServerHello from the network. Returns an unsigned char array on success (which the caller must free()), or NULL on failure. */ -bs *getServerHello(int s) { - bs *server_hello = NULL; - bs_new_size(&server_hello, 512); +/* Adds default key_share extension. */ +void tlsExtensionAddDefaultKeyShare(bs *tls_extensions) { + + bs_append_bytes(tls_extensions, (unsigned char []) { + 0x00, 0x33, // key_share (51) + 0x00, 0x26, // Length (38) + 0x00, 0x24, // Key Share List Length (36) + 0x00, 0x1d, // Group ID (X25519) + 0x00, 0x20, // Key Exchange Length (32) + }, 10); + + /* Add 32 bytes of the (bogus) X25519 key share. */ + srand(time(NULL) ^ 0xbeefdead); + for (int i = 0; i < 32; i++) { + unsigned char c = (unsigned char)rand(); + bs_append_bytes(tls_extensions, &c, 1); + } - /* Read in the first 5 bytes to get the length of the rest of the packet. */ - int err = bs_read_socket(server_hello, s, 5); + /* Update the length of the extensions. */ + tlsExtensionUpdateLength(tls_extensions); +} + +/* Retrieves a TLS Handshake record, or returns NULL on error. */ +bs *getTLSHandshakeRecord(int s) { + bs *tls_record = NULL; + bs_new_size(&tls_record, 512); + + /* Read in the first 5 bytes to get the length of the rest of the record. */ + int err = bs_read_socket(tls_record, s, 5); if (err != 0) goto err; /* Ensure that the Content Type is Handshake (22). */ - if (bs_get_byte(server_hello, 0) != 0x16) + if (bs_get_byte(tls_record, 0) != 0x16) goto err; - /* Get the length of the Server Hello record. */ - unsigned short packet_len = (bs_get_byte(server_hello, 3) << 8) | bs_get_byte(server_hello, 4); + /* Get the length of the record. */ + unsigned short packet_len = (bs_get_byte(tls_record, 3) << 8) | bs_get_byte(tls_record, 4); - /* Read in the rest of the Server Hello. */ - err = bs_read_socket(server_hello, s, packet_len); + /* Read in the rest of the record. */ + err = bs_read_socket(tls_record, s, packet_len); if (err != 0) goto err; + return tls_record; + + err: + bs_free(&tls_record); + return NULL; +} + +/* Update the length of the TLS extensions. */ +void tlsExtensionUpdateLength(bs *tls_extensions) { + bs_set_ushort(tls_extensions, 0, bs_get_len(tls_extensions) - 2); +} + +/* From socket s, reads a ServerHello from the network. Returns a byte string on success (which the caller must bs_free()), or NULL on failure. */ +bs *getServerHello(int s) { + bs *server_hello = getTLSHandshakeRecord(s); + + if (server_hello == NULL) + goto err; + /* Ensure that the Handshake Type is Server Hello (2). */ if (bs_get_byte(server_hello, 5) != 0x02) goto err; @@ -4830,17 +5052,17 @@ bs *getServerHello(int s) { return NULL; } -/* Returns a byte string (which the caller must later free) containing a TLS Client Hello message. The number of bytes is stored in 'client_hello_len'. 'version' is set to 0 for TLSv1.0, 1 for TLSv1.1, 2, for TLSv1.2, and 3 for TLSv1.3. The specified ciphersuite list and TLS extensions will be included. */ -bs *makeClientHello(struct sslCheckOptions *options, unsigned int version, bs *ciphersuite_list, bs *tls_extensions) { +/* Returns a byte string (which the caller must later bs_free()) containing a TLS Client Hello message. The 'tls_version' must be one of the TLSv1_? constants. The specified ciphersuite list and TLS extensions will be included. */ +bs *makeClientHello(struct sslCheckOptions *options, unsigned int tls_version, bs *ciphersuite_list, bs *tls_extensions) { bs *client_hello = NULL; unsigned int tls_record_version_low_byte = 1, tls_handshake_version_low_byte = 1; time_t time_now = time(NULL); /* For TLSv1.0, 1.1, and 1.2, the TLS Record version and Handshake version are the same (and what they should be). For TLSv1.3, the TLS Record claims to be TLSv1.0 and the Handshake claims to be TLSv1.2; this is for compatibility of buggy middleware that most implementations follow. */ - if (version < 3) { - tls_record_version_low_byte += version; - tls_handshake_version_low_byte += version; + if (tls_version < TLSv1_3) { + tls_record_version_low_byte += tls_version; + tls_handshake_version_low_byte += tls_version; } else { tls_record_version_low_byte = 1; tls_handshake_version_low_byte = 3; @@ -4896,19 +5118,14 @@ bs *makeClientHello(struct sslCheckOptions *options, unsigned int version, bs *c } /* Checks all ciphersuites that OpenSSL does not support. When version is 0, TLSv1.0 is tested. When set to 1, TLSv1.1 is tested. When set to 2, TLSv1.2 is tested. */ -int testMissingCiphers(struct sslCheckOptions *options, unsigned int version) { - int ret = false, s = 0; +int testMissingCiphers(struct sslCheckOptions *options, unsigned int tls_version) { + int ret = false, s = -1; unsigned int tls_version_low_byte = 1; - char *tls_printable_name = "TLSv1.0"; + char *tls_printable_name = getPrintableTLSName(tls_version); bs *client_hello = NULL, *server_hello = NULL, *ciphersuite_list = NULL, *tls_extensions = NULL; - tls_version_low_byte += version; - - if (version == 1) - tls_printable_name = "TLSv1.1"; - else if (version == 2) - tls_printable_name = "TLSv1.2"; + tls_version_low_byte += tls_version; /* Continue until a Server Hello isn't received. */ while (1) { @@ -4941,12 +5158,12 @@ int testMissingCiphers(struct sslCheckOptions *options, unsigned int version) { 0x00, 0x0a, // sect283r1 }, 32); - bs_set_ushort(tls_extensions, 0, bs_get_len(tls_extensions) - 2); + tlsExtensionUpdateLength(tls_extensions); /* Construct the list of all ciphersuites not implemented by OpenSSL. */ - ciphersuite_list = makeCiphersuiteList(version, CIPHERSUITES_MISSING); + ciphersuite_list = makeCiphersuiteListMissing(tls_version); - client_hello = makeClientHello(options, version, ciphersuite_list, tls_extensions); + client_hello = makeClientHello(options, tls_version, ciphersuite_list, tls_extensions); bs_free(&ciphersuite_list); bs_free(&tls_extensions); @@ -4999,7 +5216,7 @@ int testMissingCiphers(struct sslCheckOptions *options, unsigned int version) { bs_free(&server_hello); /* Mark this cipher ID as supported by the server, so when we loop again, the next ciphersuite list doesn't include it. */ - markFoundCiphersuite(cipher_id, version); + markFoundCiphersuite(cipher_id, tls_version); /* Get the IANA name and cipher bit strength (maybe -1 when unknown). */ cipher_name = resolveCipherID(cipher_id, &cipher_bits); @@ -5022,9 +5239,12 @@ int testMissingCiphers(struct sslCheckOptions *options, unsigned int version) { return ret; } -/* Enumerates all the group key exchanges for TLSv1.3. This could potentially be adapted to support TLSv1.0 - v1.2. */ +/* Enumerates all the group key exchanges supported by the server. Tests the highest supported protocol between TLSv1.0 and v1.2, along with TLSv1.3 (if enabled). */ int testSupportedGroups(struct sslCheckOptions *options) { - int ret = true; + int ret = true, s = -1; + unsigned int printed_header = 0; + int test_versions[2] = {-1, -1}; + bs *client_hello = NULL, *ciphersuite_list = NULL, *tls_extensions = NULL, *server_hello = NULL, *key_exchange = NULL; struct group_key_exchange { uint16_t group_id; @@ -5036,19 +5256,44 @@ int testSupportedGroups(struct sslCheckOptions *options) { uint16_t key_exchange_len; }; - /* Bit strength of DHE 2048 and 3072-bit moduli is taken directly from NIST SP 800-57 pt.1, rev4., pg. 53; DHE 4096, 6144, and 8192 are estimated using that document. */ + + /* Auto-generated by ./tools/iana_tls_supported_groups_parser.py on December 24, 2019. */ #define COL_PLAIN "" #define NID_TYPE_NA 0 /* Not Applicable (i.e.: X25519/X448) */ -#define NID_TYPE_ECDHE 1 /* For P-256/384-521. */ +#define NID_TYPE_ECDHE 1 /* For ECDHE curves (sec*, P-256/384-521) */ #define NID_TYPE_DHE 2 /* For ffdhe* */ + /* Bit strength of DHE 2048 and 3072-bit moduli is taken directly from NIST SP 800-57 pt.1, rev4., pg. 53; DHE 4096, 6144, and 8192 are estimated using that document. */ struct group_key_exchange group_key_exchanges[] = { - {0x001d, "X25519", 128, COL_GREEN, -1, NID_TYPE_NA, 32}, - {0x001e, "X448", 224, COL_GREEN, -1, NID_TYPE_NA, 56}, - - {0x0017, "secp256r1 [P-256]", 128, COL_PLAIN, NID_X9_62_prime256v1, NID_TYPE_ECDHE, 0}, - {0x0018, "secp384r1 [P-384]", 192, COL_PLAIN, NID_secp384r1, NID_TYPE_ECDHE, 0}, - {0x0019, "secp521r1 [P-521]", 256, COL_PLAIN, NID_secp521r1, NID_TYPE_ECDHE, 0}, - + {0x0001, "sect163k1", 81, COL_RED, NID_sect163k1, NID_TYPE_ECDHE, 0}, + {0x0002, "sect163r1", 81, COL_RED, NID_sect163r1, NID_TYPE_ECDHE, 0}, + {0x0003, "sect163r2", 81, COL_RED, NID_sect163r2, NID_TYPE_ECDHE, 0}, + {0x0004, "sect193r1", 96, COL_RED, NID_sect193r1, NID_TYPE_ECDHE, 0}, + {0x0005, "sect193r2", 96, COL_RED, NID_sect193r2, NID_TYPE_ECDHE, 0}, + {0x0006, "sect233k1", 116, COL_PLAIN, NID_sect233k1, NID_TYPE_ECDHE, 0}, + {0x0007, "sect233r1", 116, COL_PLAIN, NID_sect233r1, NID_TYPE_ECDHE, 0}, + {0x0008, "sect239k1", 119, COL_PLAIN, NID_sect239k1, NID_TYPE_ECDHE, 0}, + {0x0009, "sect283k1", 141, COL_PLAIN, NID_sect283k1, NID_TYPE_ECDHE, 0}, + {0x000a, "sect283r1", 141, COL_PLAIN, NID_sect283r1, NID_TYPE_ECDHE, 0}, + {0x000b, "sect409k1", 204, COL_PLAIN, NID_sect409k1, NID_TYPE_ECDHE, 0}, + {0x000c, "sect409r1", 204, COL_PLAIN, NID_sect409r1, NID_TYPE_ECDHE, 0}, + {0x000d, "sect571k1", 285, COL_PLAIN, NID_sect571k1, NID_TYPE_ECDHE, 0}, + {0x000e, "sect571r1", 285, COL_PLAIN, NID_sect571r1, NID_TYPE_ECDHE, 0}, + {0x000f, "secp160k1", 80, COL_RED, NID_secp160k1, NID_TYPE_ECDHE, 0}, + {0x0010, "secp160r1", 80, COL_RED, NID_secp160r1, NID_TYPE_ECDHE, 0}, + {0x0011, "secp160r2", 80, COL_RED, NID_secp160r2, NID_TYPE_ECDHE, 0}, + {0x0012, "secp192k1", 96, COL_RED, NID_secp192k1, NID_TYPE_ECDHE, 0}, + {0x0013, "secp192r1", 96, COL_RED, NID_X9_62_prime192v1, NID_TYPE_ECDHE, 0}, + {0x0014, "secp224k1", 112, COL_PLAIN, NID_secp224k1, NID_TYPE_ECDHE, 0}, + {0x0015, "secp224r1", 112, COL_PLAIN, NID_secp224r1, NID_TYPE_ECDHE, 0}, + {0x0016, "secp256k1", 128, COL_GREEN, NID_secp256k1, NID_TYPE_ECDHE, 0}, + {0x0017, "secp256r1 (NIST P-256)", 128, COL_PLAIN, NID_X9_62_prime256v1, NID_TYPE_ECDHE, 0}, + {0x0018, "secp384r1 (NIST P-384)", 192, COL_PLAIN, NID_secp384r1, NID_TYPE_ECDHE, 0}, + {0x0019, "secp521r1 (NIST P-521)", 260, COL_PLAIN, NID_secp521r1, NID_TYPE_ECDHE, 0}, + {0x001a, "brainpoolP256r1", 128, COL_PLAIN, NID_brainpoolP256r1, NID_TYPE_ECDHE, 0}, + {0x001b, "brainpoolP384r1", 192, COL_PLAIN, NID_brainpoolP384r1, NID_TYPE_ECDHE, 0}, + {0x001c, "brainpoolP512r1", 256, COL_PLAIN, NID_brainpoolP512r1, NID_TYPE_ECDHE, 0}, + {0x001d, "x25519", 128, COL_GREEN, -1, NID_TYPE_NA, 32}, + {0x001e, "x448", 224, COL_GREEN, -1, NID_TYPE_NA, 56}, {0x0100, "ffdhe2048", 112, COL_PLAIN, NID_ffdhe2048, NID_TYPE_DHE, 256}, {0x0101, "ffdhe3072", 128, COL_PLAIN, NID_ffdhe3072, NID_TYPE_DHE, 384}, {0x0102, "ffdhe4096", 150, COL_PLAIN, NID_ffdhe4096, NID_TYPE_DHE, 512}, @@ -5056,160 +5301,247 @@ int testSupportedGroups(struct sslCheckOptions *options) { {0x0104, "ffdhe8192", 192, COL_PLAIN, NID_ffdhe8192, NID_TYPE_DHE, 1024}, }; - unsigned int printed_header = 0; - int s = 0; - bs *client_hello = NULL, *ciphersuite_list = NULL, *tls_extensions = NULL, *server_hello = NULL, *key_exchange = NULL; + /* If TLSv1.3 is supported, test it first. */ + unsigned int index = 0; + if (options->tls13_supported) { + test_versions[index] = TLSv1_3; + index++; + } - /* Get all TLSv1.3 ciphersuites. */ - ciphersuite_list = makeCiphersuiteList(3, CIPHERSUITES_TLSV1_3_ALL); - - /* For each key exchange group... */ - for (int i = 0; i < (sizeof(group_key_exchanges) / sizeof(struct group_key_exchange)); i++) { - uint16_t group_id = group_key_exchanges[i].group_id; - char *group_name = group_key_exchanges[i].group_name; - char *color = group_key_exchanges[i].color; - unsigned int group_bit_strength = group_key_exchanges[i].group_bit_strength; - int nid = group_key_exchanges[i].nid; - unsigned nid_type = group_key_exchanges[i].nid_type; - uint16_t key_exchange_len = group_key_exchanges[i].key_exchange_len; - - /* This will hold the key exchange data that we send to the server. */ - bs_new_size(&key_exchange, key_exchange_len); - - /* Generate the right type of key exchange data. */ - if (nid_type == NID_TYPE_NA) { - - /* Generate "random" data. X25519 and X448 public keys have no discernible structure. */ - srand(time(NULL) ^ 0xdeadbeef); - for (int j = 0; j < key_exchange_len; j++) { - unsigned char c = (unsigned char)rand(); - bs_append_bytes(key_exchange, &c, 1); - } + /* For TLSv1.2 and below, test the highest protocol version supported. */ + if (options->tls12_supported) + test_versions[index] = TLSv1_2; + else if (options->tls11_supported) + test_versions[index] = TLSv1_1; + else if (options->tls10_supported) + test_versions[index] = TLSv1_0; - } else if (nid_type == NID_TYPE_ECDHE) { + /* Loop through the one or two TLS versions to test. */ + for (index = 0; index < (sizeof(test_versions) / sizeof(int)); index++) { + int tls_version = test_versions[index]; - /* Generate the ECDHE key. */ - EC_KEY *key = EC_KEY_new_by_curve_name(nid); - if ((key == NULL) || (EC_KEY_generate_key(key) != 1)) { - EC_KEY_free(key); key = NULL; - fprintf(stderr, "Failed to generate ECDHE key for nid %d\n", nid); - continue; - } + /* If there's only one version to test... */ + if (tls_version == -1) + break; + + if (tls_version == TLSv1_3) + ciphersuite_list = makeCiphersuiteListAll(tls_version); + else { + /* For some reason, with TLSv1.2 (and maybe below), passing all ciphersuites causes false negatives. So we use a string of bytes sniffed from an OpenSSL client connection. */ + bs_new(&ciphersuite_list); + bs_append_bytes(ciphersuite_list, (unsigned char []) { 0xc0, 0x30, 0xc0, 0x2c, 0xc0, 0x28, 0xc0, 0x24, 0xc0, 0x14, 0xc0, 0x0a, 0x00, 0xa5, 0x00, 0xa3, 0x00, 0xa1, 0x00, 0x9f, 0x00, 0x6b, 0x00, 0x6a, 0x00, 0x69, 0x00, 0x68, 0x00, 0x39, 0x00, 0x38, 0x00, 0x37, 0x00, 0x36, 0x00, 0x88, 0x00, 0x87, 0x00, 0x86, 0x00, 0x85, 0xc0, 0x32, 0xc0, 0x2e, 0xc0, 0x2a, 0xc0, 0x26, 0xc0, 0x0f, 0xc0, 0x05, 0x00, 0x9d, 0x00, 0x3d, 0x00, 0x35, 0x00, 0x84, 0xc0, 0x2f, 0xc0, 0x2b, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x13, 0xc0, 0x09, 0x00, 0xa4, 0x00, 0xa2, 0x00, 0xa0, 0x00, 0x9e, 0x00, 0x67, 0x00, 0x40, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x33, 0x00, 0x32, 0x00, 0x31, 0x00, 0x30, 0x00, 0x9a, 0x00, 0x99, 0x00, 0x98, 0x00, 0x97, 0x00, 0x45, 0x00, 0x44, 0x00, 0x43, 0x00, 0x42, 0xc0, 0x31, 0xc0, 0x2d, 0xc0, 0x29, 0xc0, 0x25, 0xc0, 0x0e, 0xc0, 0x04, 0x00, 0x9c, 0x00, 0x3c, 0x00, 0x2f, 0x00, 0x96, 0x00, 0x41, 0xc0, 0x11, 0xc0, 0x07, 0xc0, 0x0c, 0xc0, 0x02, 0x00, 0x05, 0x00, 0x04, 0xc0, 0x12, 0xc0, 0x08, 0x00, 0x16, 0x00, 0x13, 0x00, 0x10, 0x00, 0x0d, 0xc0, 0x0d, 0xc0, 0x03, 0x00, 0x0a, 0x00, 0xff }, 170); + } + + /* For each key exchange group... */ + for (int i = 0; i < (sizeof(group_key_exchanges) / sizeof(struct group_key_exchange)); i++) { + uint16_t group_id = group_key_exchanges[i].group_id; + char *group_name = group_key_exchanges[i].group_name; + char *color = group_key_exchanges[i].color; + unsigned int group_bit_strength = group_key_exchanges[i].group_bit_strength; + int nid = group_key_exchanges[i].nid; + unsigned nid_type = group_key_exchanges[i].nid_type; + uint16_t key_exchange_len = group_key_exchanges[i].key_exchange_len; + + /* This will hold the key exchange data that we send to the server. */ + bs_new_size(&key_exchange, key_exchange_len); + + /* Generate the right type of key exchange data. */ + if (nid_type == NID_TYPE_NA) { + + /* Generate "random" data. X25519 and X448 public keys have no discernible structure. */ + srand(time(NULL) ^ 0xdeadbeef); + for (int j = 0; j < key_exchange_len; j++) { + unsigned char c = (unsigned char)rand(); + bs_append_bytes(key_exchange, &c, 1); + } + + } else if (nid_type == NID_TYPE_ECDHE) { + + /* Generate the ECDHE key. */ + EC_KEY *key = EC_KEY_new_by_curve_name(nid); + if ((key == NULL) || (EC_KEY_generate_key(key) != 1)) { + EC_KEY_free(key); key = NULL; + fprintf(stderr, "Failed to generate ECDHE key for nid %d\n", nid); + continue; + } + + /* Allocate a *new* byte array and put the key into it. */ + unsigned char *kex_buf = NULL; + key_exchange_len = EC_KEY_key2buf(key, POINT_CONVERSION_UNCOMPRESSED, &kex_buf, NULL); + if (kex_buf == NULL) { + EC_KEY_free(key); key = NULL; + fprintf(stderr, "Failed to obtain ECDHE public key bytes.\n"); + continue; + } - /* Allocate a *new* byte array and put the key into it. */ - unsigned char *kex_buf = NULL; - key_exchange_len = EC_KEY_key2buf(key, POINT_CONVERSION_UNCOMPRESSED, &kex_buf, NULL); - if (kex_buf == NULL) { + bs_append_bytes(key_exchange, kex_buf, key_exchange_len); + OPENSSL_free(kex_buf); kex_buf = NULL; EC_KEY_free(key); key = NULL; - fprintf(stderr, "Failed to obtain ECDHE public key bytes.\n"); - continue; - } - bs_append_bytes(key_exchange, kex_buf, key_exchange_len); - OPENSSL_free(kex_buf); kex_buf = NULL; - EC_KEY_free(key); key = NULL; + } else if (nid_type == NID_TYPE_DHE) { - } else if (nid_type == NID_TYPE_DHE) { + /* The value (Y) for FFDHE group must be 1 < Y < p - 1 (see RFC7919). Furthermore, GnuTLS checks that Y ^ q mod p == 1 (see GnuTLS v3.6.11.1, lib/nettle/pk.c:291). The easiest way to do this seems to be to actually generate real DH public keys. */ + DH *dh = DH_new_by_nid(nid); + if (!DH_generate_key(dh)) { + bs_free(&key_exchange); + fprintf(stderr, "Failed to generate DH key for nid %d\n", nid); + continue; + } - /* The value (Y) for FFDHE group must be 1 < Y < p - 1 (see RFC7919). Furthermore, GnuTLS checks that Y ^ q mod p == 1 (see GnuTLS v3.6.11.1, lib/nettle/pk.c:291). The easiest way to do this seems to be to actually generate real DH public keys. */ - DH *dh = DH_new_by_nid(nid); - if (!DH_generate_key(dh)) { - bs_free(&key_exchange); - fprintf(stderr, "Failed to generate DH key for nid %d\n", nid); - continue; - } + /* Make array to read in DH public key. */ + unsigned int bytes_len = key_exchange_len; + unsigned char *bytes = calloc(bytes_len, sizeof(unsigned char)); + if (bytes == NULL) { + fprintf(stderr, "Failed to allocate buffer for key.\n"); + exit(-1); + } - /* Make array to read in DH public key. */ - unsigned int bytes_len = key_exchange_len; - unsigned char *bytes = calloc(bytes_len, sizeof(unsigned char)); - if (bytes == NULL) { - fprintf(stderr, "Failed to allocate buffer for key.\n"); - exit(-1); + /* Export the public key to our array. */ + const BIGNUM *pub_key = NULL; + DH_get0_key(dh, &pub_key, NULL); + if (!BN_bn2binpad(pub_key, bytes, bytes_len)) { + bs_free(&key_exchange); + fprintf(stderr, "Failed to get DH key for nid %d\n", nid); + continue; + } + + /* Add the bytes to our byte string. */ + bs_append_bytes(key_exchange, bytes, bytes_len); + FREE(bytes); bytes_len = 0; + + } else { + /* Use the provided value, since it must be a specific format. */ + fprintf(stderr, "Error: unknown NID_TYPE in struct: %d\n", nid_type); + exit(-1); } - /* Export the public key to our array. */ - const BIGNUM *pub_key = NULL; - DH_get0_key(dh, &pub_key, NULL); - if (!BN_bn2binpad(pub_key, bytes, bytes_len)) { - bs_free(&key_exchange); - fprintf(stderr, "Failed to get DH key for nid %d\n", nid); - continue; + /* Make generic TLS extensions (with SNI, accepted EC point formats, etc). */ + tls_extensions = makeTLSExtensions(options, 1); + + /* Add the supported_versions extension to signify we are using TLS v1.3. */ + if (tls_version == TLSv1_3) + tlsExtensionAddTLSv1_3(tls_extensions); + + /* Add the supported_groups extension. Only add the one group we are testing for. */ + bs_append_bytes(tls_extensions, (unsigned char []) { + 0x00, 0x0a, // Extension Type: supported_groups (10) + 0x00, 0x04, // Extension Length (4) + 0x00, 0x02, // Supported Groups List Length (2) + }, 6); + bs_append_ushort(tls_extensions, group_id); + + /* Only add the key_share extension if we're using TLS v1.3. */ + if (tls_version == TLSv1_3) { + /* Add the key_share extension for the current group type. */ + bs_append_bytes(tls_extensions, (unsigned char []) { 0x00, 0x33 }, 2); // Extension Type: key_share (51) + bs_append_ushort(tls_extensions, bs_get_len(key_exchange) + 6); // Extension Length + bs_append_ushort(tls_extensions, bs_get_len(key_exchange) + 4); // Client Key Share Length + bs_append_ushort(tls_extensions, group_id); // Group ID. + bs_append_ushort(tls_extensions, bs_get_len(key_exchange)); // Key Exchange Length + bs_append_bs(tls_extensions, key_exchange); // Key Exchange } + bs_free(&key_exchange); - /* Add the bytes to our byte string. */ - bs_append_bytes(key_exchange, bytes, bytes_len); - FREE(bytes); bytes_len = 0; + /* Update the TLS extensions length since we manually added to it. */ + tlsExtensionUpdateLength(tls_extensions); - } else { - /* Use the provided value, since it must be a specific format. */ - fprintf(stderr, "Error: unknown NID_TYPE in struct: %d\n", nid_type); - exit(-1); - } + /* Create the Client Hello buffer using the ciphersuite list and TLS extensions. */ + client_hello = makeClientHello(options, tls_version, ciphersuite_list, tls_extensions); - /* Make generic TLS extensions (with SNI, accepted EC point formats, etc). */ - tls_extensions = makeTLSExtensions(options, 1); + /* Free the TLS extensions since we're done with them. Note: we don't free the ciphersuite_list because we'll need them on the next loop. */ + bs_free(&tls_extensions); - /* Add the supported_versions extension to signify we are using TLS v1.3. */ - tlsExtensionAddTLSv1_3(tls_extensions); + CLOSE(s); /* In case the last loop left the socket open. */ - /* Add the supported_groups extension. Only add the one group we are testing for. */ - bs_append_bytes(tls_extensions, (unsigned char []) { - 0x00, 0x0a, // Extension Type: supported_groups (10) - 0x00, 0x04, // Extension Length (4) - 0x00, 0x02, // Supported Groups List Length (2) - }, 6); - bs_append_ushort(tls_extensions, group_id); + /* Now connect to the target server. */ + s = tcpConnect(options); + if (s == 0) { + ret = false; + goto done; + } - /* Add the key_share extension for the current group type. */ - bs_append_bytes(tls_extensions, (unsigned char []) { 0x00, 0x33 }, 2); // Extension Type: key_share (51) - bs_append_ushort(tls_extensions, bs_get_len(key_exchange) + 6); // Extension Length - bs_append_ushort(tls_extensions, bs_get_len(key_exchange) + 4); // Client Key Share Length - bs_append_ushort(tls_extensions, group_id); // Group ID. - bs_append_ushort(tls_extensions, bs_get_len(key_exchange)); // Key Exchange Length - bs_append_bs(tls_extensions, key_exchange); // Key Exchange + /* Send the Client Hello message. */ + if (send(s, bs_get_bytes(client_hello), bs_get_len(client_hello), 0) <= 0) { + printf_error("send() failed while sending Client Hello: %d (%s)\n", errno, strerror(errno)); + ret = false; + goto done; + } + bs_free(&client_hello); - bs_free(&key_exchange); + server_hello = getServerHello(s); - /* Update the TLS extensions length since we manually added to it. */ - bs_set_ushort(tls_extensions, 0, bs_get_len(tls_extensions) - 2); + /* This group is definitely not supported. */ + if (server_hello == NULL) { + CLOSE(s); + continue; + } - /* Create the Client Hello buffer using the ciphersuite list and TLS extensions. */ - client_hello = makeClientHello(options, 3, ciphersuite_list, tls_extensions); + bs_free(&server_hello); - /* Free the TLS extensions since we're done with them. Note: we don't free the ciphersuite_list because we'll need them on the next loop. */ - bs_free(&tls_extensions); + /* For TLSv1.2 and below, we need to examine the Server Key Exchange record. */ + if (tls_version < TLSv1_3) { + bs *tls_record = getTLSHandshakeRecord(s); + unsigned int handshake_type = bs_get_byte(tls_record, 5); + if (handshake_type == 14) { /* Server Hello Done */ + bs_free(&tls_record); + CLOSE(s); + continue; + } - /* Now connect to the target server. */ - s = tcpConnect(options); - if (s == 0) { - ret = false; - goto done; - } + /* Skip all records that aren't Server Key Exchanges (type 12). */ + while ((tls_record != NULL) && (bs_get_byte(tls_record, 5) != 12)) { + bs_free(&tls_record); + tls_record = getTLSHandshakeRecord(s); + handshake_type = bs_get_byte(tls_record, 5); + if (handshake_type == 14) { /* Server Hello Done */ + bs_free(&tls_record); + CLOSE(s); + continue; + } + } - /* Send the Client Hello message. */ - if (send(s, bs_get_bytes(client_hello), bs_get_len(client_hello), 0) <= 0) { - printf_error("send() failed while sending Client Hello: %d (%s)\n", errno, strerror(errno)); - ret = false; - goto done; - } - bs_free(&client_hello); + /* Error, so skip this group. */ + if (tls_record == NULL) { + bs_free(&tls_record); + CLOSE(s); + continue; + } - server_hello = getServerHello(s); - CLOSE(s); + /* If this Server Key Exchange does not have a named_curve (3) field, skip this group. */ + if (bs_get_byte(tls_record, 9) != 3) { + bs_free(&tls_record); + CLOSE(s); + continue; + } - /* This group is not supported. */ - if (server_hello == NULL) - continue; + /* Check that the named_curve result is the group we requested. */ + uint16_t server_group_id = bs_get_byte(tls_record, 10) << 8 | bs_get_byte(tls_record, 11); + if (server_group_id != group_id) { + bs_free(&tls_record); + CLOSE(s); + continue; + } - bs_free(&server_hello); + bs_free(&tls_record); + } + CLOSE(s); - if (!printed_header) { - printf("\n %sServer Key Exchange Group(s):%s\n", COL_BLUE, RESET); - printed_header = 1; + if (!printed_header) { + printf("\n %sServer Key Exchange Group(s):%s\n", COL_BLUE, RESET); + printed_header = 1; + } + + char *bits_color = RESET; + if (group_bit_strength < 112) + bits_color = COL_RED; + else + bits_color = COL_GREEN; + + char *printable_TLS_name = getPrintableTLSName(tls_version); + printf("%s %s%d%s bits %s%s%s\n", printable_TLS_name, bits_color, group_bit_strength, RESET, color, group_name, RESET); + printf_xml(" \n", printable_TLS_name, group_bit_strength, group_name, group_id); } - printf("%s%s%s (%d bits)\n", color, group_name, RESET, group_bit_strength); - printf_xml(" \n", group_bit_strength, group_name, group_id); } done: @@ -5261,12 +5593,12 @@ int testSignatureAlgorithms(struct sslCheckOptions *options) { }; unsigned int printed_header = 0; - int s = 0; + int s = -1; bs *client_hello = NULL, *ciphersuite_list = NULL, *tls_extensions = NULL, *server_hello = NULL; /* Get all TLSv1.3 ciphersuites. */ - ciphersuite_list = makeCiphersuiteList(3, CIPHERSUITES_TLSV1_3_ALL); + ciphersuite_list = makeCiphersuiteListTLS13All(); /* For each signature algorithm... */ for (int i = 0; i < (sizeof(signature_algorithms) / sizeof(struct signature_algorithm)); i++) { @@ -5295,18 +5627,8 @@ int testSignatureAlgorithms(struct sslCheckOptions *options) { 0x01, 0x04, // FFDHE8192 }, 26); - /* Extension: key_share */ - bs_append_bytes(tls_extensions, (unsigned char []) { - 0x00, 0x33, // Extension: key_share (51) - 0x00, 0x26, // Extension Length (37) - 0x00, 0x24, // Key Share List Length (36) - 0x00, 0x1d, // Group ID (X25519) - 0x00, 0x20, // Key Exchange Length (32) - }, 10); - - /* Add 32 bytes of the (bogus) X25519 key share. */ - for (unsigned int j = 0; j < (32 / sizeof(uint32_t)); j++) - bs_append_uint32_t(tls_extensions, 0x029a029a); + /* Add key shares for X25519. */ + tlsExtensionAddDefaultKeyShare(tls_extensions); /* Add the supported_versions extension to signify we are using TLS v1.3. */ tlsExtensionAddTLSv1_3(tls_extensions); @@ -5320,7 +5642,7 @@ int testSignatureAlgorithms(struct sslCheckOptions *options) { bs_append_ushort(tls_extensions, sig_id); /* Update the TLS extensions length since we manually added to it. */ - bs_set_ushort(tls_extensions, 0, bs_get_len(tls_extensions) - 2); + tlsExtensionUpdateLength(tls_extensions); /* Create the Client Hello buffer using the ciphersuite list and TLS extensions. */ client_hello = makeClientHello(options, 3, ciphersuite_list, tls_extensions); diff --git a/sslscan.h b/sslscan.h index b8c4d98..7d9b4ee 100644 --- a/sslscan.h +++ b/sslscan.h @@ -50,6 +50,7 @@ #define BUFFERSIZE 1024 +// For options.sslVersion field. #define ssl_all 0 #define ssl_v2 1 #define ssl_v3 2 @@ -59,6 +60,12 @@ #define tls_v12 6 #define tls_v13 7 +// For functions that take a tls_version argument. +#define TLSv1_0 0 +#define TLSv1_1 1 +#define TLSv1_2 2 +#define TLSv1_3 3 + /* We must maintain our own list of TLSv1.3-specific ciphersuites here, because SSL_CTX_get_ciphers() will *always* return TLSv1.2 ciphersuites, even when SSL_CTX_set_min_proto_version() and SSL_CTX_set_max_proto_version() are used. This is confirmed by an OpenSSL developer here: https://github.com/openssl/openssl/issues/7196#issuecomment-420575202 */ #define TLSV13_CIPHERSUITES "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256" @@ -72,7 +79,7 @@ #define printf_verbose(format, ...) if (options->verbose) printf(format, ##__VA_ARGS__) /* Calls close() on a file descriptor, then sets it to zero to prevent accidental re-use. */ -#define CLOSE(fd) { if ((fd) != 0) { close((fd)); (fd) = 0; } } +#define CLOSE(fd) { if ((fd) != -1) { close((fd)); (fd) = -1; } } /* Calls free() on a pointer, then explicitly sets it to NULL to avoid use-after-free. */ #define FREE(ptr) { free((ptr)); (ptr) = NULL; } @@ -190,6 +197,12 @@ struct sslCheckOptions char *clientCertsFile; char *privateKeyFile; char *privateKeyPassword; + + // TLS versions supported by the server. + unsigned int tls10_supported; + unsigned int tls11_supported; + unsigned int tls12_supported; + unsigned int tls13_supported; }; // store renegotiation test data @@ -298,10 +311,17 @@ unsigned char bs_get_byte(bs *, size_t); void bs_set_byte(bs *, size_t, unsigned char); void bs_set_ushort(bs *b, size_t offset, unsigned short length); int bs_read_socket(bs *b, int s, size_t num_bytes); +unsigned int checkIfTLSVersionIsSupported(struct sslCheckOptions *options, unsigned int tls_version); SSL_CTX *CTX_new(const SSL_METHOD *method); int fileExists(char *); void findMissingCiphers(); -void makeMissingCiphersuiteList(unsigned char **ciphersuite_list, size_t *ciphersuite_list_len, unsigned int tls_version); +char *getPrintableTLSName(unsigned int tls_version); +bs *getServerHello(int s); +bs *makeCiphersuiteListAll(unsigned int tls_version); +bs *makeCiphersuiteListTLS13All(); +bs *makeCiphersuiteListMissing(unsigned int tls_version); +bs *makeClientHello(struct sslCheckOptions *options, unsigned int version, bs *ciphersuite_list, bs *tls_extensions); +bs *makeTLSExtensions(struct sslCheckOptions *options, unsigned int include_signature_algorithms); void markFoundCiphersuite(unsigned short server_cipher_id, unsigned int tls_version); int ocsp_certid_print(BIO *bp, OCSP_CERTID *a, int indent); static int ocsp_resp_cb(SSL *s, void *arg); @@ -312,6 +332,9 @@ static int password_callback(char *, int, int, void *); const char *printableSslMethod(const SSL_METHOD *); ssize_t sendString(int, const char[]); int ssl_print_tmp_key(struct sslCheckOptions *, SSL *s); +void tlsExtensionAddDefaultKeyShare(bs *tls_extensions); +void tlsExtensionAddTLSv1_3(bs *tls_extensions); +void tlsExtensionUpdateLength(bs *tls_extensions); int tcpConnect(struct sslCheckOptions *); // Tests diff --git a/tools/iana_tls_supported_groups_parser.py b/tools/iana_tls_supported_groups_parser.py new file mode 100755 index 0000000..c766c30 --- /dev/null +++ b/tools/iana_tls_supported_groups_parser.py @@ -0,0 +1,126 @@ +#!/usr/bin/python3 + +# +# Copyright (C) 2019 Joe Testa +# +# This tool will parse the list of TLS supported groups from IANA +# (https://www.iana.org/assignments/tls-parameters/tls-parameters-8.csv) into a C-struct +# for use in testSupportedGroups(). +# + +import csv, sys +from datetime import date + + +# We must be given a path to a CSV file with the groups. It can be obtained from +# . +if len(sys.argv) != 2: + print("\nUsage: %s tls_ciphers.csv\n\nHint: copy the TLS table in CSV format from .\n" % sys.argv[0]) + exit(0) + +csv_file = sys.argv[1] + +print() +print(" /* Auto-generated by %s on %s. */" % (sys.argv[0], date.today().strftime("%B %d, %Y"))) +print('#define COL_PLAIN ""') +print('#define NID_TYPE_NA 0 /* Not Applicable (i.e.: X25519/X448) */') +print('#define NID_TYPE_ECDHE 1 /* For ECDHE curves (sec*, P-256/384-521) */') +print('#define NID_TYPE_DHE 2 /* For ffdhe* */') +print(" /* Bit strength of DHE 2048 and 3072-bit moduli is taken directly from NIST SP 800-57 pt.1, rev4., pg. 53; DHE 4096, 6144, and 8192 are estimated using that document. */") +print(" struct group_key_exchange group_key_exchanges[] = {") +with open(csv_file, 'r') as f: + reader = csv.reader(f) + for row in reader: + id = row[0] + group_name = row[1] + reference = row[4] + + # Skip the header. + try: + int(id) + except ValueError as e: + continue + + id = int(id) + + # Skip reserved or unassigned IDs. + if group_name in ('Reserved', 'Unassigned'): + continue + + # The Reference field looks like "[RFC1234]", "[draft-blah-blah]", or "[RFC-ietf-tls-blah-02]". Skip all rows that aren't of the "[RFC1234]" variety. + reference = reference[1:] + rt_bracket_pos = reference.find(']') + if rt_bracket_pos == -1: + print("Warning: can't parse reference: %s" % reference) + else: + reference = reference[3:rt_bracket_pos] + + try: + int(reference) + except ValueError as e: + continue + + bits = 0 + nid = "NID_x" + nid_type = "NID_TYPE_x" + key_exchange_len = 0 + color = "COL_PLAIN" + if group_name.startswith('sec'): + bits = int(group_name[4:-2]) / 2 + nid = "NID_%s" % group_name + nid_type = "NID_TYPE_ECDHE" + if group_name == "secp192r1": + nid = "NID_X9_62_prime192v1" + elif group_name == "secp256r1": + nid = "NID_X9_62_prime256v1" + group_name += ' (NIST P-256)' + elif group_name == "secp256k1": + color = "COL_GREEN" # This is the very well-tested Bitcoin curve. + elif group_name == "secp384r1": + group_name += ' (NIST P-384)' + elif group_name == "secp521r1": + group_name += ' (NIST P-521)' + elif group_name.startswith('brainpoolP'): + bits = int(group_name[10:-2]) / 2 + nid = "NID_%s" % group_name + nid_type = "NID_TYPE_ECDHE" + elif group_name in ('x25519', 'x448'): + color = "COL_GREEN" + nid = "-1" + nid_type = "NID_TYPE_NA" + if group_name == 'x25519': + bits = 128 + key_exchange_len = 32 + elif group_name == 'x448': + bits = 224 + key_exchange_len = 56 + elif group_name.startswith('ffdhe'): + # Bit strength of DHE 2048 and 3072-bit moduli is taken directly from NIST SP 800-57 pt.1, rev4., pg. 53; DHE 4096, 6144, and 8192 are estimated using that document. + if group_name == 'ffdhe2048': + bits = 112 + key_exchange_len = 256 + elif group_name == 'ffdhe3072': + bits = 128 + key_exchange_len = 384 + elif group_name == 'ffdhe4096': + bits = 150 + key_exchange_len = 512 + elif group_name == 'ffdhe6144': + bits = 175 + key_exchange_len = 768 + elif group_name == 'ffdhe8192': + bits = 192 + key_exchange_len = 1024 + nid = "NID_%s" % group_name + nid_type = "NID_TYPE_DHE" + elif group_name.startswith('arbitrary_'): # Skip these two. + continue + + if bits < 112: + color = "COL_RED" + + print(' {0x%04x, "%s", %d, %s, %s, %s, %d},' % (id, group_name, bits, color, nid, nid_type, key_exchange_len)) + +print(" };") +print() +exit(0) From 0fd82c715584411e99d89c85bf5b762efbdfdd05 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Wed, 15 Jan 2020 16:00:49 -0500 Subject: [PATCH 42/52] Fixed docker testing on Arch. Tests now run against 127.0.0.1 instead of localhost (which sometimes resolved to ::1 and broke the test). OpenSSL repo cloning now done with '--depth 1'. --- docker_test.sh | 41 +++++++++++++++++++------ docker_test/expected_output/test_1.txt | 2 +- docker_test/expected_output/test_10.txt | 2 +- docker_test/expected_output/test_12.txt | 2 +- docker_test/expected_output/test_13.txt | 2 +- docker_test/expected_output/test_14.txt | 2 +- docker_test/expected_output/test_15.txt | 2 +- docker_test/expected_output/test_16.txt | 2 +- docker_test/expected_output/test_17.txt | 2 +- docker_test/expected_output/test_2.txt | 2 +- docker_test/expected_output/test_3.txt | 2 +- docker_test/expected_output/test_4.txt | 2 +- docker_test/expected_output/test_5.txt | 2 +- docker_test/expected_output/test_6.txt | 2 +- docker_test/expected_output/test_7.txt | 2 +- docker_test/expected_output/test_8.txt | 2 +- docker_test/expected_output/test_9.txt | 2 +- 17 files changed, 48 insertions(+), 25 deletions(-) diff --git a/docker_test.sh b/docker_test.sh index 43f529b..413a92b 100755 --- a/docker_test.sh +++ b/docker_test.sh @@ -1,7 +1,7 @@ #!/bin/bash # -# Copyright (C) 2019 Joe Testa +# Copyright (C) 2019-2020 Joe Testa # # This script (adapted from the ssh-audit project) will set up a docker image with # multiple SSL/TLS servers. They are each executed one at a time, and sslscan is run @@ -102,7 +102,7 @@ function compile_openssl { # Download OpenSSL from github. echo -e "\n${YELLOWB}Downloading OpenSSL v${version}...${CLR}\n" - git clone -b $git_tag https://github.com/openssl/openssl/ $output_dir + git clone --depth 1 -b $git_tag https://github.com/openssl/openssl/ $output_dir # Configure and compile it. echo -e "\n\n${YELLOWB}Compiling OpenSSL v${version} with \"-j ${compile_num_procs}\"...${CLR}" @@ -204,7 +204,7 @@ function compile_gnutls { pushd $gnutls_source_dir nettle_source_dir_abs=`readlink -m ../nettle` nettle_parent_dir=`readlink -m ..` - NETTLE_CFLAGS=-I${nettle_parent_dir} NETTLE_LIBS="-L${nettle_source_dir_abs} -lnettle" HOGWEED_CFLAGS=-I${nettle_parent_dir} HOGWEED_LIBS="-L${nettle_source_dir_abs} -lhogweed" ./configure --with-included-libtasn1 --with-included-unistring --without-p11-kit + NETTLE_CFLAGS=-I${nettle_parent_dir} NETTLE_LIBS="-L${nettle_source_dir_abs} -lnettle" HOGWEED_CFLAGS=-I${nettle_parent_dir} HOGWEED_LIBS="-L${nettle_source_dir_abs} -lhogweed" ./configure --with-included-libtasn1 --with-included-unistring --without-p11-kit --disable-guile make CFLAGS=-I${nettle_parent_dir} LDFLAGS="-L${nettle_source_dir_abs} -lhogweed -lnettle" -j $compile_num_procs # Ensure that the gnutls-serv and gnutls-cli tools were built @@ -411,7 +411,7 @@ function run_test { # Run sslscan and cut out the first two lines. Those contain the version number # and local version of OpenSSL, which can change over time (and when they do, this # would break the test if they were left in). - ./sslscan $sslscan_additional_args localhost:4443 | tail -n +3 > $test_result_stdout + ./sslscan $sslscan_additional_args 127.0.0.1:4443 | tail -n +3 > $test_result_stdout if [[ $? != 0 ]]; then echo -e "${REDB}Failed to run sslscan! (exit code: $?)${CLR}" docker container stop -t 0 $cid > /dev/null @@ -486,11 +486,34 @@ if [[ $? != 0 ]]; then exit 1 fi -# Ensure that the libgmp-dev and m4 packages are installed. -dpkg -l libgmp-dev m4 > /dev/null -if [[ $? != 0 ]]; then - echo -e "${REDB}Error: libgmp-dev and/or m4 packages not installed. Fix with: apt install libgmp-dev m4${CLR}" - exit 1 +is_debian=0 +is_arch=0 + +# If dpkg exists, assume this is a Debian-based system. +dpkg --version > /dev/null 2>&1 +if [[ $? == 0 ]]; then + is_debian=1 +fi + +# If pacman exists, assume this is an Arch system. +pacman --version > /dev/null 2>&1 +if [[ ($is_debian == 0) && ($? == 0) ]]; then + is_arch=1 +fi + +# Ensure that the libgmp-dev, m4, and wget packages are installed. Use dpkg on Debian, or pacman on Arch. +if [[ $is_debian == 1 ]]; then + dpkg -l libgmp-dev m4 perl wget > /dev/null 2>&1 + if [[ $? != 0 ]]; then + echo -e "${REDB}Error: libgmp-dev, m4, perl and/or wget packages not installed. Fix with: apt install libgmp-dev m4 perl wget${CLR}" + exit 1 + fi +elif [[ $is_arch == 1 ]]; then + pacman -Qi gmp m4 perl wget > /dev/null 2>&1 + if [[ $? != 0 ]]; then + echo -e "${REDB}Error: gmp, m4, perl and/or wget packages not installed. Fix with: pacman -S gmp m4 perl wget${CLR}" + exit 1 + fi fi # Make sure sslscan has been built. diff --git a/docker_test/expected_output/test_1.txt b/docker_test/expected_output/test_1.txt index 604667f..0209219 100644 --- a/docker_test/expected_output/test_1.txt +++ b/docker_test/expected_output/test_1.txt @@ -1,7 +1,7 @@  Connected to 127.0.0.1 -Testing SSL server localhost on port 4443 using SNI name localhost +Testing SSL server 127.0.0.1 on port 4443 using SNI name 127.0.0.1 SSL/TLS Protocols: SSLv2 is not enabled diff --git a/docker_test/expected_output/test_10.txt b/docker_test/expected_output/test_10.txt index 88dcec4..efa60e7 100644 --- a/docker_test/expected_output/test_10.txt +++ b/docker_test/expected_output/test_10.txt @@ -1,7 +1,7 @@  Connected to 127.0.0.1 -Testing SSL server localhost on port 4443 using SNI name localhost +Testing SSL server 127.0.0.1 on port 4443 using SNI name 127.0.0.1 SSL/TLS Protocols: SSLv2 is not enabled diff --git a/docker_test/expected_output/test_12.txt b/docker_test/expected_output/test_12.txt index c337873..9f30641 100644 --- a/docker_test/expected_output/test_12.txt +++ b/docker_test/expected_output/test_12.txt @@ -1,7 +1,7 @@  Connected to 127.0.0.1 -Testing SSL server localhost on port 4443 using SNI name localhost +Testing SSL server 127.0.0.1 on port 4443 using SNI name 127.0.0.1 SSL/TLS Protocols: SSLv2 is enabled diff --git a/docker_test/expected_output/test_13.txt b/docker_test/expected_output/test_13.txt index 51e5f24..359a9dc 100644 --- a/docker_test/expected_output/test_13.txt +++ b/docker_test/expected_output/test_13.txt @@ -1,7 +1,7 @@  Connected to 127.0.0.1 -Testing SSL server localhost on port 4443 using SNI name localhost +Testing SSL server 127.0.0.1 on port 4443 using SNI name 127.0.0.1 SSL/TLS Protocols: SSLv2 is not enabled diff --git a/docker_test/expected_output/test_14.txt b/docker_test/expected_output/test_14.txt index 49d1a5f..d4c0763 100644 --- a/docker_test/expected_output/test_14.txt +++ b/docker_test/expected_output/test_14.txt @@ -1,7 +1,7 @@  Connected to 127.0.0.1 -Testing SSL server localhost on port 4443 using SNI name localhost +Testing SSL server 127.0.0.1 on port 4443 using SNI name 127.0.0.1 SSL/TLS Protocols: SSLv2 is not enabled diff --git a/docker_test/expected_output/test_15.txt b/docker_test/expected_output/test_15.txt index de33a1a..a332369 100644 --- a/docker_test/expected_output/test_15.txt +++ b/docker_test/expected_output/test_15.txt @@ -1,7 +1,7 @@  Connected to 127.0.0.1 -Testing SSL server localhost on port 4443 using SNI name localhost +Testing SSL server 127.0.0.1 on port 4443 using SNI name 127.0.0.1 SSL/TLS Protocols: SSLv2 is not enabled diff --git a/docker_test/expected_output/test_16.txt b/docker_test/expected_output/test_16.txt index 55bac8a..33fb250 100644 --- a/docker_test/expected_output/test_16.txt +++ b/docker_test/expected_output/test_16.txt @@ -1,7 +1,7 @@  Connected to 127.0.0.1 -Testing SSL server localhost on port 4443 using SNI name localhost +Testing SSL server 127.0.0.1 on port 4443 using SNI name 127.0.0.1 SSL/TLS Protocols: SSLv2 is not enabled diff --git a/docker_test/expected_output/test_17.txt b/docker_test/expected_output/test_17.txt index c5302cb..337d6ea 100644 --- a/docker_test/expected_output/test_17.txt +++ b/docker_test/expected_output/test_17.txt @@ -1,7 +1,7 @@  Connected to 127.0.0.1 -Testing SSL server localhost on port 4443 using SNI name localhost +Testing SSL server 127.0.0.1 on port 4443 using SNI name 127.0.0.1 SSL/TLS Protocols: SSLv2 is not enabled diff --git a/docker_test/expected_output/test_2.txt b/docker_test/expected_output/test_2.txt index 4e2b891..2436c45 100644 --- a/docker_test/expected_output/test_2.txt +++ b/docker_test/expected_output/test_2.txt @@ -1,7 +1,7 @@  Connected to 127.0.0.1 -Testing SSL server localhost on port 4443 using SNI name localhost +Testing SSL server 127.0.0.1 on port 4443 using SNI name 127.0.0.1 SSL/TLS Protocols: SSLv2 is enabled diff --git a/docker_test/expected_output/test_3.txt b/docker_test/expected_output/test_3.txt index aa5d0f5..8566e7e 100644 --- a/docker_test/expected_output/test_3.txt +++ b/docker_test/expected_output/test_3.txt @@ -1,7 +1,7 @@  Connected to 127.0.0.1 -Testing SSL server localhost on port 4443 using SNI name localhost +Testing SSL server 127.0.0.1 on port 4443 using SNI name 127.0.0.1 SSL/TLS Protocols: SSLv2 is not enabled diff --git a/docker_test/expected_output/test_4.txt b/docker_test/expected_output/test_4.txt index 010f1f2..2ca0f3f 100644 --- a/docker_test/expected_output/test_4.txt +++ b/docker_test/expected_output/test_4.txt @@ -1,7 +1,7 @@  Connected to 127.0.0.1 -Testing SSL server localhost on port 4443 using SNI name localhost +Testing SSL server 127.0.0.1 on port 4443 using SNI name 127.0.0.1 SSL/TLS Protocols: SSLv2 is not enabled diff --git a/docker_test/expected_output/test_5.txt b/docker_test/expected_output/test_5.txt index 686cc12..7ce7084 100644 --- a/docker_test/expected_output/test_5.txt +++ b/docker_test/expected_output/test_5.txt @@ -1,7 +1,7 @@  Connected to 127.0.0.1 -Testing SSL server localhost on port 4443 using SNI name localhost +Testing SSL server 127.0.0.1 on port 4443 using SNI name 127.0.0.1 SSL/TLS Protocols: SSLv2 is not enabled diff --git a/docker_test/expected_output/test_6.txt b/docker_test/expected_output/test_6.txt index 4e52bc1..5d0f794 100644 --- a/docker_test/expected_output/test_6.txt +++ b/docker_test/expected_output/test_6.txt @@ -1,7 +1,7 @@  Connected to 127.0.0.1 -Testing SSL server localhost on port 4443 using SNI name localhost +Testing SSL server 127.0.0.1 on port 4443 using SNI name 127.0.0.1 SSL/TLS Protocols: SSLv2 is not enabled diff --git a/docker_test/expected_output/test_7.txt b/docker_test/expected_output/test_7.txt index 5fb44bc..4d13e6a 100644 --- a/docker_test/expected_output/test_7.txt +++ b/docker_test/expected_output/test_7.txt @@ -1,7 +1,7 @@  Connected to 127.0.0.1 -Testing SSL server localhost on port 4443 using SNI name localhost +Testing SSL server 127.0.0.1 on port 4443 using SNI name 127.0.0.1 SSL/TLS Protocols: SSLv2 is enabled diff --git a/docker_test/expected_output/test_8.txt b/docker_test/expected_output/test_8.txt index 60cf251..d250072 100644 --- a/docker_test/expected_output/test_8.txt +++ b/docker_test/expected_output/test_8.txt @@ -1,7 +1,7 @@  Connected to 127.0.0.1 -Testing SSL server localhost on port 4443 using SNI name localhost +Testing SSL server 127.0.0.1 on port 4443 using SNI name 127.0.0.1 SSL/TLS Protocols: SSLv2 is enabled diff --git a/docker_test/expected_output/test_9.txt b/docker_test/expected_output/test_9.txt index 0a10aa2..69d540e 100644 --- a/docker_test/expected_output/test_9.txt +++ b/docker_test/expected_output/test_9.txt @@ -1,7 +1,7 @@  Connected to 127.0.0.1 -Testing SSL server localhost on port 4443 using SNI name localhost +Testing SSL server 127.0.0.1 on port 4443 using SNI name 127.0.0.1 SSL/TLS Protocols: SSLv2 is not enabled From 536e147c785711f04846cdddbf9ff137b1f1d70a Mon Sep 17 00:00:00 2001 From: rbsec Date: Sat, 18 Jan 2020 19:17:33 +0000 Subject: [PATCH 43/52] Update readme --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 55de7f8..33713b7 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ +# Beta Branch + +This is a beta branch for the major rewrite by @jtesta to add in TLSv1.3 support (as well as other features). + +There may be bugs and other issues. Any feedback is greatly appreciated. + # README [![Build Status](https://travis-ci.org/rbsec/sslscan.svg?branch=master)](https://travis-ci.org/rbsec/sslscan) From fcad50021613a44971d2c6790ce501ec4a8e6b0e Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Tue, 21 Jan 2020 10:45:33 -0500 Subject: [PATCH 44/52] Server signature algorithms now enumerated for TLSv1.2 and below. --- docker_test.sh | 7 + docker_test/expected_output/test_1.txt | 17 ++ docker_test/expected_output/test_12.txt | 3 + docker_test/expected_output/test_13.txt | 7 +- docker_test/expected_output/test_14.txt | 7 +- docker_test/expected_output/test_15.txt | 6 +- docker_test/expected_output/test_16.txt | 17 ++ docker_test/expected_output/test_17.txt | 9 ++ docker_test/expected_output/test_18.txt | 45 ++++++ docker_test/expected_output/test_4.txt | 14 +- docker_test/expected_output/test_5.txt | 17 ++ docker_test/expected_output/test_6.txt | 6 +- docker_test/expected_output/test_7.txt | 3 + docker_test/expected_output/test_8.txt | 3 + sslscan.c | 205 ++++++++++++++---------- 15 files changed, 266 insertions(+), 100 deletions(-) create mode 100644 docker_test/expected_output/test_18.txt diff --git a/docker_test.sh b/docker_test.sh index 413a92b..80c3cd3 100755 --- a/docker_test.sh +++ b/docker_test.sh @@ -275,6 +275,7 @@ function run_tests { run_test_15 "0" run_test_16 "0" run_test_17 "0" + run_test_18 "0" } @@ -380,6 +381,12 @@ function run_test_17 { } +# TLSv1.2 with ECDSA-SHA1 signature only. +function run_test_18 { + run_test $1 '18' "/gnutls-3.6.11.1/gnutls-serv -p 443 --x509certfile=/etc/ssl/cert_ecdsa_prime256v1.crt --x509keyfile=/etc/ssl/key_ecdsa_prime256v1.pem --priority=NONE:-VERS-TLS1.0:-VERS-TLS1.1:+VERS-TLS1.2:-VERS-TLS1.3:+MAC-ALL:+GROUP-ALL:+SIGN-ECDSA-SHA1:+COMP-NULL:+CTYPE-SRV-ALL:+KX-ALL:+CHACHA20-POLY1305:+CAMELLIA-128-GCM:+AES-128-GCM" "" +} + + # Run a test. Set the first argument to '1' to enable test debugging. # Second argument is the test number to run. Third argument is the executable and # its args to be run inside the container.. diff --git a/docker_test/expected_output/test_1.txt b/docker_test/expected_output/test_1.txt index 0209219..f799dbf 100644 --- a/docker_test/expected_output/test_1.txt +++ b/docker_test/expected_output/test_1.txt @@ -98,6 +98,23 @@ Accepted TLSv1.0 112 bits DES-CBC3-SHA Server Key Exchange Group(s): TLSv1.2 128 bits secp256r1 (NIST P-256) + Server Signature Algorithm(s): +TLSv1.2 rsa_pkcs1_sha1 +TLSv1.2 dsa_sha1 +TLSv1.2 ecdsa_sha1 +TLSv1.2 rsa_pkcs1_sha224 +TLSv1.2 dsa_sha224 +TLSv1.2 ecdsa_sha224 +TLSv1.2 rsa_pkcs1_sha256 +TLSv1.2 dsa_sha256 +TLSv1.2 ecdsa_secp256r1_sha256 +TLSv1.2 rsa_pkcs1_sha384 +TLSv1.2 dsa_sha384 +TLSv1.2 ecdsa_secp384r1_sha384 +TLSv1.2 rsa_pkcs1_sha512 +TLSv1.2 dsa_sha512 +TLSv1.2 ecdsa_secp521r1_sha512 + SSL Certificate: Signature Algorithm: sha256WithRSAEncryption RSA Key Strength: 2048 diff --git a/docker_test/expected_output/test_12.txt b/docker_test/expected_output/test_12.txt index 9f30641..f606561 100644 --- a/docker_test/expected_output/test_12.txt +++ b/docker_test/expected_output/test_12.txt @@ -49,6 +49,9 @@ Accepted TLSv1.0 56 bits TLS_DHE_RSA_WITH_DES_CBC_SHA Server Key Exchange Group(s): TLSv1.0 128 bits secp256r1 (NIST P-256) + Server Signature Algorithm(s): +TLSv1.0 Server accepts all signature algorithms. + SSL Certificate: Signature Algorithm: md5WithRSAEncryption RSA Key Strength: 512 diff --git a/docker_test/expected_output/test_13.txt b/docker_test/expected_output/test_13.txt index 359a9dc..ec94512 100644 --- a/docker_test/expected_output/test_13.txt +++ b/docker_test/expected_output/test_13.txt @@ -78,9 +78,10 @@ TLSv1.2 260 bits secp521r1 (NIST P-521) TLSv1.2 128 bits x25519 Server Signature Algorithm(s): -rsa_pss_rsae_sha256 -rsa_pss_rsae_sha384 -rsa_pss_rsae_sha512 +TLSv1.3 rsa_pss_rsae_sha256 +TLSv1.3 rsa_pss_rsae_sha384 +TLSv1.3 rsa_pss_rsae_sha512 +TLSv1.2 Server accepts all signature algorithms. SSL Certificate: Signature Algorithm: sha256WithRSAEncryption diff --git a/docker_test/expected_output/test_14.txt b/docker_test/expected_output/test_14.txt index d4c0763..d31d47a 100644 --- a/docker_test/expected_output/test_14.txt +++ b/docker_test/expected_output/test_14.txt @@ -54,9 +54,10 @@ TLSv1.3 192 bits ffdhe8192 TLSv1.2 260 bits secp521r1 (NIST P-521) Server Signature Algorithm(s): -rsa_pss_rsae_sha256 -rsa_pss_rsae_sha384 -rsa_pss_rsae_sha512 +TLSv1.3 rsa_pss_rsae_sha256 +TLSv1.3 rsa_pss_rsae_sha384 +TLSv1.3 rsa_pss_rsae_sha512 +TLSv1.2 Server accepts all signature algorithms. SSL Certificate: Signature Algorithm: sha256WithRSAEncryption diff --git a/docker_test/expected_output/test_15.txt b/docker_test/expected_output/test_15.txt index a332369..afea69a 100644 --- a/docker_test/expected_output/test_15.txt +++ b/docker_test/expected_output/test_15.txt @@ -59,7 +59,11 @@ TLSv1.2 260 bits secp521r1 (NIST P-521) TLSv1.2 128 bits x25519 Server Signature Algorithm(s): -ecdsa_secp256r1_sha256 +TLSv1.3 ecdsa_secp256r1_sha256 +TLSv1.2 ecdsa_sha1 +TLSv1.2 ecdsa_secp256r1_sha256 +TLSv1.2 ecdsa_secp384r1_sha384 +TLSv1.2 ecdsa_secp521r1_sha512 SSL Certificate: Signature Algorithm: sha256WithRSAEncryption diff --git a/docker_test/expected_output/test_16.txt b/docker_test/expected_output/test_16.txt index 33fb250..adb15b5 100644 --- a/docker_test/expected_output/test_16.txt +++ b/docker_test/expected_output/test_16.txt @@ -50,6 +50,23 @@ Accepted TLSv1.2 112 bits DES-CBC3-SHA  Server Key Exchange Group(s): TLSv1.2 81 bits sect163k1 + Server Signature Algorithm(s): +TLSv1.2 rsa_pkcs1_sha1 +TLSv1.2 dsa_sha1 +TLSv1.2 ecdsa_sha1 +TLSv1.2 rsa_pkcs1_sha224 +TLSv1.2 dsa_sha224 +TLSv1.2 ecdsa_sha224 +TLSv1.2 rsa_pkcs1_sha256 +TLSv1.2 dsa_sha256 +TLSv1.2 ecdsa_secp256r1_sha256 +TLSv1.2 rsa_pkcs1_sha384 +TLSv1.2 dsa_sha384 +TLSv1.2 ecdsa_secp384r1_sha384 +TLSv1.2 rsa_pkcs1_sha512 +TLSv1.2 dsa_sha512 +TLSv1.2 ecdsa_secp521r1_sha512 + SSL Certificate: Signature Algorithm: sha256WithRSAEncryption RSA Key Strength: 1024 diff --git a/docker_test/expected_output/test_17.txt b/docker_test/expected_output/test_17.txt index 337d6ea..c8229b7 100644 --- a/docker_test/expected_output/test_17.txt +++ b/docker_test/expected_output/test_17.txt @@ -41,6 +41,15 @@ Accepted TLSv1.2 128 bits AES128-SHA Server Key Exchange Group(s): TLSv1.2 256 bits brainpoolP512r1 + Server Signature Algorithm(s): +TLSv1.2 rsa_pkcs1_sha1 +TLSv1.2 rsa_pkcs1_sha224 +TLSv1.2 rsa_pkcs1_sha256 +TLSv1.2 rsa_pkcs1_sha384 +TLSv1.2 rsa_pkcs1_sha512 +TLSv1.2 rsa_pss_rsae_sha256 +TLSv1.2 rsa_pss_rsae_sha384 + SSL Certificate: Signature Algorithm: sha256WithRSAEncryption RSA Key Strength: 1024 diff --git a/docker_test/expected_output/test_18.txt b/docker_test/expected_output/test_18.txt new file mode 100644 index 0000000..2eb2b0b --- /dev/null +++ b/docker_test/expected_output/test_18.txt @@ -0,0 +1,45 @@ + +Connected to 127.0.0.1 + +Testing SSL server 127.0.0.1 on port 4443 using SNI name 127.0.0.1 + + SSL/TLS Protocols: +SSLv2 is not enabled +SSLv3 is not enabled +TLSv1.0 is not enabled +TLSv1.1 is not enabled +TLSv1.2 is enabled +TLSv1.3 is not enabled + + TLS Fallback SCSV: +Server supports TLS Fallback SCSV + + TLS renegotiation: +Session renegotiation not supported + + TLS Compression: +Compression disabled + + Heartbleed: +TLS 1.2 not vulnerable to heartbleed + + Supported Server Cipher(s): +Preferred TLSv1.2 256 bits ECDHE-ECDSA-CHACHA20-POLY1305 Curve 25519 DHE 253 +Accepted TLSv1.2 128 bits ECDHE-ECDSA-AES128-GCM-SHA256 Curve 25519 DHE 253 +Accepted TLSv1.2 128 bits TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + + Server Key Exchange Group(s): +TLSv1.2 128 bits secp256r1 (NIST P-256) +TLSv1.2 192 bits secp384r1 (NIST P-384) +TLSv1.2 260 bits secp521r1 (NIST P-521) +TLSv1.2 128 bits x25519 + + Server Signature Algorithm(s): +TLSv1.2 ecdsa_sha1 + + SSL Certificate: +Signature Algorithm: sha256WithRSAEncryption +Subject: itspeanutbutterjellytime.com +Issuer: /C=XX/ST=Nowhere in particular/L=Nowhere +Not valid before: Dec 22 19:01:56 2019 GMT +Not valid after: Dec 22 19:01:56 2029 GMT diff --git a/docker_test/expected_output/test_4.txt b/docker_test/expected_output/test_4.txt index 2ca0f3f..d68fed9 100644 --- a/docker_test/expected_output/test_4.txt +++ b/docker_test/expected_output/test_4.txt @@ -76,9 +76,17 @@ TLSv1.2 128 bits x25519 TLSv1.2 224 bits x448 Server Signature Algorithm(s): -rsa_pss_rsae_sha256 -rsa_pss_rsae_sha384 -rsa_pss_rsae_sha512 +TLSv1.3 rsa_pss_rsae_sha256 +TLSv1.3 rsa_pss_rsae_sha384 +TLSv1.3 rsa_pss_rsae_sha512 +TLSv1.2 rsa_pkcs1_sha1 +TLSv1.2 rsa_pkcs1_sha224 +TLSv1.2 rsa_pkcs1_sha256 +TLSv1.2 rsa_pkcs1_sha384 +TLSv1.2 rsa_pkcs1_sha512 +TLSv1.2 rsa_pss_rsae_sha256 +TLSv1.2 rsa_pss_rsae_sha384 +TLSv1.2 rsa_pss_rsae_sha512 SSL Certificate: Signature Algorithm: sha256WithRSAEncryption diff --git a/docker_test/expected_output/test_5.txt b/docker_test/expected_output/test_5.txt index 7ce7084..b1dcea0 100644 --- a/docker_test/expected_output/test_5.txt +++ b/docker_test/expected_output/test_5.txt @@ -153,6 +153,23 @@ Accepted TLSv1.0 56 bits TLS_DH_anon_WITH_DES_CBC_SHA Server Key Exchange Group(s): TLSv1.2 128 bits secp256r1 (NIST P-256) + Server Signature Algorithm(s): +TLSv1.2 rsa_pkcs1_sha1 +TLSv1.2 dsa_sha1 +TLSv1.2 ecdsa_sha1 +TLSv1.2 rsa_pkcs1_sha224 +TLSv1.2 dsa_sha224 +TLSv1.2 ecdsa_sha224 +TLSv1.2 rsa_pkcs1_sha256 +TLSv1.2 dsa_sha256 +TLSv1.2 ecdsa_secp256r1_sha256 +TLSv1.2 rsa_pkcs1_sha384 +TLSv1.2 dsa_sha384 +TLSv1.2 ecdsa_secp384r1_sha384 +TLSv1.2 rsa_pkcs1_sha512 +TLSv1.2 dsa_sha512 +TLSv1.2 ecdsa_secp521r1_sha512 + SSL Certificate: Signature Algorithm: sha256WithRSAEncryption RSA Key Strength: 1024 diff --git a/docker_test/expected_output/test_6.txt b/docker_test/expected_output/test_6.txt index 5d0f794..b6bf355 100644 --- a/docker_test/expected_output/test_6.txt +++ b/docker_test/expected_output/test_6.txt @@ -38,9 +38,9 @@ TLSv1.3 128 bits x25519 TLSv1.3 224 bits x448 Server Signature Algorithm(s): -rsa_pss_rsae_sha256 -rsa_pss_rsae_sha384 -rsa_pss_rsae_sha512 +TLSv1.3 rsa_pss_rsae_sha256 +TLSv1.3 rsa_pss_rsae_sha384 +TLSv1.3 rsa_pss_rsae_sha512 SSL Certificate: Signature Algorithm: sha256WithRSAEncryption diff --git a/docker_test/expected_output/test_7.txt b/docker_test/expected_output/test_7.txt index 4d13e6a..de5de11 100644 --- a/docker_test/expected_output/test_7.txt +++ b/docker_test/expected_output/test_7.txt @@ -49,6 +49,9 @@ Accepted TLSv1.0 56 bits TLS_DHE_RSA_WITH_DES_CBC_SHA Server Key Exchange Group(s): TLSv1.0 128 bits secp256r1 (NIST P-256) + Server Signature Algorithm(s): +TLSv1.0 Server accepts all signature algorithms. + SSL Certificate: Signature Algorithm: sha256WithRSAEncryption RSA Key Strength: 3072 diff --git a/docker_test/expected_output/test_8.txt b/docker_test/expected_output/test_8.txt index d250072..82aacab 100644 --- a/docker_test/expected_output/test_8.txt +++ b/docker_test/expected_output/test_8.txt @@ -71,6 +71,9 @@ Accepted TLSv1.0 56 bits TLS_DH_anon_WITH_DES_CBC_SHA Server Key Exchange Group(s): TLSv1.0 128 bits secp256r1 (NIST P-256) + Server Signature Algorithm(s): +TLSv1.0 Server accepts all signature algorithms. + SSL Certificate: Signature Algorithm: sha256WithRSAEncryption RSA Key Strength: 3072 diff --git a/sslscan.c b/sslscan.c index 63f74f9..140c2d9 100644 --- a/sslscan.c +++ b/sslscan.c @@ -3550,7 +3550,7 @@ int testHost(struct sslCheckOptions *options) testSupportedGroups(options); // Enumerate signature algorithms. - if (options->signature_algorithms && options->tls13_supported) + if (options->signature_algorithms) testSignatureAlgorithms(options); // Print certificate @@ -4686,13 +4686,9 @@ int bs_read_socket(bs *b, int s, size_t num_bytes) { unsigned int checkIfTLSVersionIsSupported(struct sslCheckOptions *options, unsigned int tls_version) { bs *tls_extensions = NULL, *ciphersuite_list = NULL, *client_hello = NULL, *server_hello = NULL; int ret = false, s = -1; - unsigned int include_server_signatures = 0; - if (tls_version == TLSv1_3) - include_server_signatures = 1; - - tls_extensions = makeTLSExtensions(options, include_server_signatures); + tls_extensions = makeTLSExtensions(options, 1); if (tls_version == TLSv1_2) { /* Extension: supported_groups */ bs_append_bytes(tls_extensions, (unsigned char []) { @@ -5555,7 +5551,6 @@ int testSupportedGroups(struct sslCheckOptions *options) { /* Enumerates all the signature algorithms supported by the server. */ int testSignatureAlgorithms(struct sslCheckOptions *options) { - int ret = true; struct signature_algorithm { uint16_t sig_id; @@ -5567,20 +5562,26 @@ int testSignatureAlgorithms(struct sslCheckOptions *options) { #define BOGUS_SIG_ALG_ID 0xfdff /* Last un-assigned ID. */ struct signature_algorithm signature_algorithms[] = { {BOGUS_SIG_ALG_ID, "bogus", COL_RED}, /* Tests if the server is accepting all. */ + {0x0001, "rsa_pkcs1_nohash", COL_RED}, + {0x0002, "dsa_nohash", COL_RED}, + {0x0003, "ecdsa_nohash", COL_RED}, + {0x0101, "rsa_pkcs1_md5", COL_RED}, + {0x0102, "dsa_md5", COL_RED}, + {0x0103, "ecdsa_md5", COL_RED}, {0x0201, "rsa_pkcs1_sha1", COL_RED}, - {0x0202, "SHA1 DSA", COL_RED}, + {0x0202, "dsa_sha1", COL_RED}, {0x0203, "ecdsa_sha1", COL_RED}, - {0x0301, "SHA224 ECDSA", COL_YELLOW}, - {0x0302, "SHA224 DSA", COL_RED}, - {0x0303, "SHA224 ECDSA", COL_YELLOW}, + {0x0301, "rsa_pkcs1_sha224", COL_YELLOW}, + {0x0302, "dsa_sha224", COL_RED}, + {0x0303, "ecdsa_sha224", COL_YELLOW}, {0x0401, "rsa_pkcs1_sha256", COL_PLAIN}, - {0x0402, "SHA256 DSA", COL_RED}, + {0x0402, "dsa_sha256", COL_RED}, {0x0403, "ecdsa_secp256r1_sha256", COL_PLAIN}, {0x0501, "rsa_pkcs1_sha384", COL_PLAIN}, - {0x0502, "SHA384 DSA", COL_RED}, + {0x0502, "dsa_sha384", COL_RED}, {0x0503, "ecdsa_secp384r1_sha384", COL_PLAIN}, {0x0601, "rsa_pkcs1_sha512", COL_PLAIN}, - {0x0602, "SHA512 DSA", COL_RED}, + {0x0602, "dsa_sha512", COL_RED}, {0x0603, "ecdsa_secp521r1_sha512", COL_PLAIN}, {0x0804, "rsa_pss_rsae_sha256", COL_PLAIN}, {0x0805, "rsa_pss_rsae_sha384", COL_PLAIN}, @@ -5593,99 +5594,129 @@ int testSignatureAlgorithms(struct sslCheckOptions *options) { }; unsigned int printed_header = 0; - int s = -1; + int ret = true, s = -1; + int test_versions[2] = {-1, -1}; bs *client_hello = NULL, *ciphersuite_list = NULL, *tls_extensions = NULL, *server_hello = NULL; + /* If TLSv1.3 is supported, test it first. */ + unsigned int index = 0; + if (options->tls13_supported) { + test_versions[index] = TLSv1_3; + index++; + } - /* Get all TLSv1.3 ciphersuites. */ - ciphersuite_list = makeCiphersuiteListTLS13All(); + /* For TLSv1.2 and below, test the highest protocol version supported. */ + if (options->tls12_supported) + test_versions[index] = TLSv1_2; + else if (options->tls11_supported) + test_versions[index] = TLSv1_1; + else if (options->tls10_supported) + test_versions[index] = TLSv1_0; + + /* Loop through the one or two TLS versions to test. */ + for (index = 0; index < (sizeof(test_versions) / sizeof(int)); index++) { + int tls_version = test_versions[index]; - /* For each signature algorithm... */ - for (int i = 0; i < (sizeof(signature_algorithms) / sizeof(struct signature_algorithm)); i++) { - uint16_t sig_id = signature_algorithms[i].sig_id; - char *sig_name = signature_algorithms[i].sig_name; - char *color = signature_algorithms[i].color; + /* If there's only one version to test... */ + if (tls_version == -1) + break; + if (tls_version == TLSv1_3) { + /* Get all TLSv1.3 ciphersuites. */ + ciphersuite_list = makeCiphersuiteListTLS13All(); + } else + ciphersuite_list = makeCiphersuiteListAll(tls_version); - /* Make generic TLS extensions (with SNI, accepted EC point formats, etc). */ - tls_extensions = makeTLSExtensions(options, 0); - /* Extension: supported_groups */ - bs_append_bytes(tls_extensions, (unsigned char []) { - 0x00, 0x0a, // Extension: supported_groups (10) - 0x00, 0x16, // Extension Length (22) - 0x00, 0x14, // Supported Groups List Length (20) - 0x00, 0x17, // secp256r1 - 0x00, 0x19, // secp521r1 - 0x00, 0x18, // secp384r1 - 0x00, 0x1d, // X25519 - 0x00, 0x1e, // X448 - 0x01, 0x00, // FFDHE2048 - 0x01, 0x01, // FFDHE3072 - 0x01, 0x02, // FFDHE4096 - 0x01, 0x03, // FFDHE6144 - 0x01, 0x04, // FFDHE8192 - }, 26); + /* For each signature algorithm... */ + for (int i = 0; i < (sizeof(signature_algorithms) / sizeof(struct signature_algorithm)); i++) { + uint16_t sig_id = signature_algorithms[i].sig_id; + char *sig_name = signature_algorithms[i].sig_name; + char *color = signature_algorithms[i].color; - /* Add key shares for X25519. */ - tlsExtensionAddDefaultKeyShare(tls_extensions); - /* Add the supported_versions extension to signify we are using TLS v1.3. */ - tlsExtensionAddTLSv1_3(tls_extensions); + /* Make generic TLS extensions (with SNI, accepted EC point formats, etc). */ + tls_extensions = makeTLSExtensions(options, 0); - /* Add the signature_algorithms extension. Only add the one group we are testing for. */ - bs_append_bytes(tls_extensions, (unsigned char []) { - 0x00, 0x0d, // Extension Type: signature_algorithms (13) - 0x00, 0x04, // Extension Length (4) - 0x00, 0x02, // Signature Hash Algorithms List Length (2) - }, 6); - bs_append_ushort(tls_extensions, sig_id); + if (tls_version == TLSv1_3) { + /* Extension: supported_groups */ + bs_append_bytes(tls_extensions, (unsigned char []) { + 0x00, 0x0a, // Extension: supported_groups (10) + 0x00, 0x16, // Extension Length (22) + 0x00, 0x14, // Supported Groups List Length (20) + 0x00, 0x17, // secp256r1 + 0x00, 0x19, // secp521r1 + 0x00, 0x18, // secp384r1 + 0x00, 0x1d, // X25519 + 0x00, 0x1e, // X448 + 0x01, 0x00, // FFDHE2048 + 0x01, 0x01, // FFDHE3072 + 0x01, 0x02, // FFDHE4096 + 0x01, 0x03, // FFDHE6144 + 0x01, 0x04, // FFDHE8192 + }, 26); + + /* Add key shares for X25519. */ + tlsExtensionAddDefaultKeyShare(tls_extensions); + + /* Add the supported_versions extension to signify we are using TLS v1.3. */ + tlsExtensionAddTLSv1_3(tls_extensions); + } - /* Update the TLS extensions length since we manually added to it. */ - tlsExtensionUpdateLength(tls_extensions); + /* Add the signature_algorithms extension. Only add the one group we are testing for. */ + bs_append_bytes(tls_extensions, (unsigned char []) { + 0x00, 0x0d, // Extension Type: signature_algorithms (13) + 0x00, 0x04, // Extension Length (4) + 0x00, 0x02, // Signature Hash Algorithms List Length (2) + }, 6); + bs_append_ushort(tls_extensions, sig_id); - /* Create the Client Hello buffer using the ciphersuite list and TLS extensions. */ - client_hello = makeClientHello(options, 3, ciphersuite_list, tls_extensions); + /* Update the TLS extensions length since we manually added to it. */ + tlsExtensionUpdateLength(tls_extensions); - /* Free the TLS extensions since we're done with them. Note: we don't free the ciphersuite_list because we'll need them on the next loop. */ - bs_free(&tls_extensions); + /* Create the Client Hello buffer using the ciphersuite list and TLS extensions. */ + client_hello = makeClientHello(options, tls_version, ciphersuite_list, tls_extensions); - /* Now connect to the target server. */ - s = tcpConnect(options); - if (s == 0) { - ret = false; - goto done; - } + /* Free the TLS extensions since we're done with them. Note: we don't free the ciphersuite_list because we'll need them on the next loop. */ + bs_free(&tls_extensions); - /* Send the Client Hello message. */ - if (send(s, bs_get_bytes(client_hello), bs_get_len(client_hello), 0) <= 0) { - printf_error("send() failed while sending Client Hello: %d (%s)\n", errno, strerror(errno)); - ret = false; - goto done; - } - bs_free(&client_hello); + /* Now connect to the target server. */ + s = tcpConnect(options); + if (s == 0) { + ret = false; + goto done; + } - server_hello = getServerHello(s); - CLOSE(s); + /* Send the Client Hello message. */ + if (send(s, bs_get_bytes(client_hello), bs_get_len(client_hello), 0) <= 0) { + printf_error("send() failed while sending Client Hello: %d (%s)\n", errno, strerror(errno)); + ret = false; + goto done; + } + bs_free(&client_hello); - /* This signature algorithm is not supported. */ - if (server_hello == NULL) - continue; + server_hello = getServerHello(s); + CLOSE(s); - bs_free(&server_hello); + /* This signature algorithm is not supported. */ + if (server_hello == NULL) + continue; - if (!printed_header) { - printf("\n %sServer Signature Algorithm(s):%s\n", COL_BLUE, RESET); - printed_header = 1; - } + bs_free(&server_hello); - /* If the server accepted our bogus signature ID, then we can conclude that it will accept all of them (and not test any further). Some servers in the wild do this for some reason... */ - if (sig_id == BOGUS_SIG_ALG_ID) { - printf("%sServer accepts all signature algorithms.%s\n", COL_YELLOW, RESET); - goto done; - } else { - printf("%s%s%s\n", color, sig_name, RESET); - printf_xml(" \n", sig_name, sig_id); + if (!printed_header) { + printf("\n %sServer Signature Algorithm(s):%s\n", COL_BLUE, RESET); + printed_header = 1; + } + + /* If the server accepted our bogus signature ID, then we can conclude that it will accept all of them (and not test any further). Some servers in the wild do this for some reason... */ + if (sig_id == BOGUS_SIG_ALG_ID) { + printf("%s%s Server accepts all signature algorithms.%s\n", getPrintableTLSName(tls_version), COL_YELLOW, RESET); + goto done; + } else { + printf("%s %s%s%s\n", getPrintableTLSName(tls_version), color, sig_name, RESET); + printf_xml(" \n", getPrintableTLSName(tls_version), sig_name, sig_id); + } } } From 1e819932dcc17275e78e468f51357d6ecac4649e Mon Sep 17 00:00:00 2001 From: Florian Zavatzki Date: Thu, 20 Feb 2020 11:36:51 +0100 Subject: [PATCH 45/52] Correct wrong TLS1.3 enabled value in XML output Signed-off-by: Florian Zavatzki --- sslscan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sslscan.c b/sslscan.c index 63f74f9..046e8ee 100644 --- a/sslscan.c +++ b/sslscan.c @@ -3389,7 +3389,7 @@ int testHost(struct sslCheckOptions *options) printf_xml(" \n"); } else { printf("TLSv1.3 is not enabled\n"); - printf_xml(" \n"); + printf_xml(" \n"); } } printf("\n"); From 6beaed5a59c111242d6cfe365bb29d4f60c8e240 Mon Sep 17 00:00:00 2001 From: rbsec Date: Thu, 20 Feb 2020 19:14:25 +0000 Subject: [PATCH 46/52] Color and pad the protocol status output --- sslscan.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/sslscan.c b/sslscan.c index 63f74f9..dde4f6c 100644 --- a/sslscan.c +++ b/sslscan.c @@ -3333,10 +3333,10 @@ int testHost(struct sslCheckOptions *options) // Check if SSLv2 is enabled. if ((options->sslVersion == ssl_all) || (options->sslVersion == ssl_v2)) { if (runSSLv2Test(options)) { - printf("SSLv2 is %senabled%s\n", COL_RED, RESET); + printf("SSLv2 %senabled%s\n", COL_RED, RESET); printf_xml(" \n"); } else { - printf("SSLv2 is %snot enabled%s\n", COL_GREEN, RESET); + printf("SSLv2 %sdisabled%s\n", COL_GREEN, RESET); printf_xml(" \n"); } } @@ -3344,10 +3344,10 @@ int testHost(struct sslCheckOptions *options) // Check if SSLv3 is enabled. if ((options->sslVersion == ssl_all) || (options->sslVersion == ssl_v3)) { if (runSSLv3Test(options)) { - printf("SSLv3 is %senabled%s\n", COL_RED, RESET); + printf("SSLv3 %senabled%s\n", COL_RED, RESET); printf_xml(" \n"); } else { - printf("SSLv3 is %snot enabled%s\n", COL_GREEN, RESET); + printf("SSLv3 %sdisabled%s\n", COL_GREEN, RESET); printf_xml(" \n"); } } @@ -3355,40 +3355,40 @@ int testHost(struct sslCheckOptions *options) /* Test if TLSv1.0 through TLSv1.3 is supported. This allows us to skip unnecessary tests later. Print status of each protocol when verbose flag is set. */ if ((options->sslVersion == ssl_all) || (options->sslVersion == tls_all) || (options->sslVersion == tls_v10)) { if ((options->tls10_supported = checkIfTLSVersionIsSupported(options, TLSv1_0))) { - printf("TLSv1.0 is %senabled%s\n", COL_YELLOW, RESET); + printf("TLSv1.0 %senabled%s\n", COL_YELLOW, RESET); printf_xml(" \n"); } else { - printf("TLSv1.0 is %snot enabled%s\n", COL_GREEN, RESET); + printf("TLSv1.0 %sdisabled%s\n", COL_GREEN, RESET); printf_xml(" \n"); } } if ((options->sslVersion == ssl_all) || (options->sslVersion == tls_all) || (options->sslVersion == tls_v11)) { if ((options->tls11_supported = checkIfTLSVersionIsSupported(options, TLSv1_1))) { - printf("TLSv1.1 is enabled\n"); + printf("TLSv1.1 enabled\n"); printf_xml(" \n"); } else { - printf("TLSv1.1 is not enabled\n"); + printf("TLSv1.1 disabled\n"); printf_xml(" \n"); } } if ((options->sslVersion == ssl_all) || (options->sslVersion == tls_all) || (options->sslVersion == tls_v12)) { if ((options->tls12_supported = checkIfTLSVersionIsSupported(options, TLSv1_2))) { - printf("TLSv1.2 is enabled\n"); + printf("TLSv1.2 enabled\n"); printf_xml(" \n"); } else { - printf("TLSv1.2 is not enabled\n"); + printf("TLSv1.2 not enabled\n"); printf_xml(" \n"); } } if ((options->sslVersion == ssl_all) || (options->sslVersion == tls_all) || (options->sslVersion == tls_v13)) { if ((options->tls13_supported = checkIfTLSVersionIsSupported(options, TLSv1_3))) { - printf("TLSv1.3 is enabled\n"); + printf("TLSv1.3 %senabled%s\n", COL_GREEN, RESET); printf_xml(" \n"); } else { - printf("TLSv1.3 is not enabled\n"); + printf("TLSv1.3 disabled\n"); printf_xml(" \n"); } } From c5be16ab45bfd0c39cac7578382342af2f672b34 Mon Sep 17 00:00:00 2001 From: rbsec Date: Thu, 20 Feb 2020 19:17:47 +0000 Subject: [PATCH 47/52] Fix TLS version output in Heartbleed check --- sslscan.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sslscan.c b/sslscan.c index 2e6c2ed..82777f9 100644 --- a/sslscan.c +++ b/sslscan.c @@ -3474,23 +3474,23 @@ int testHost(struct sslCheckOptions *options) #if OPENSSL_VERSION_NUMBER >= 0x10001000L if ((options->sslVersion == ssl_all || options->sslVersion == tls_all || options->sslVersion == tls_v13) && options->tls13_supported) { - printf("TLS 1.3 "); + printf("TLSv1.3 "); status = testHeartbleed(options, TLSv1_3_client_method()); } if ((options->sslVersion == ssl_all || options->sslVersion == tls_all || options->sslVersion == tls_v12) && options->tls12_supported) { - printf("TLS 1.2 "); + printf("TLSv1.2 "); status = testHeartbleed(options, TLSv1_2_client_method()); } if ((options->sslVersion == ssl_all || options->sslVersion == tls_all || options->sslVersion == tls_v11) && options->tls11_supported) { - printf("TLS 1.1 "); + printf("TLSv1.1 "); status = testHeartbleed(options, TLSv1_1_client_method()); } #endif if ((options->sslVersion == ssl_all || options->sslVersion == tls_all || options->sslVersion == tls_v10) && options->tls10_supported) { - printf("TLS 1.0 "); + printf("TLSv1.0 "); status = testHeartbleed(options, TLSv1_client_method()); } if( options->sslVersion == ssl_v2 || options->sslVersion == ssl_v3) From f2084aa3dd7fdbd1b16dff344978a173d798dbd2 Mon Sep 17 00:00:00 2001 From: rbsec Date: Thu, 20 Feb 2020 19:29:25 +0000 Subject: [PATCH 48/52] Highlight TLSv1.3 as green in ciphersuite output --- sslscan.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sslscan.c b/sslscan.c index 82777f9..7fcc15a 100644 --- a/sslscan.c +++ b/sslscan.c @@ -1601,7 +1601,10 @@ void outputCipher(struct sslCheckOptions *options, SSL *ssl, const char *cleanSs } printf_xml(" sslversion=\"%s\"", cleanSslMethod); - if (strcmp(cleanSslMethod, "TLSv1.0") == 0) { + if (strcmp(cleanSslMethod, "TLSv1.3") == 0) { + printf("%sTLSv1.3%s ", COL_GREEN, RESET); + } + else if (strcmp(cleanSslMethod, "TLSv1.0") == 0) { printf("%sTLSv1.0%s ", COL_YELLOW, RESET); } else printf("%s ", cleanSslMethod); From 9c08afb8e8c7cd9a0762e5744c4cf0a00f777746 Mon Sep 17 00:00:00 2001 From: rbsec Date: Sat, 22 Feb 2020 10:17:18 +0000 Subject: [PATCH 49/52] Use any TLS version to get certifcates and other info. Fixes #190 --- sslscan.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/sslscan.c b/sslscan.c index 7fcc15a..24b20be 100644 --- a/sslscan.c +++ b/sslscan.c @@ -2296,9 +2296,8 @@ int ocspRequest(struct sslCheckOptions *options) sslMethod = TLSv1_3_method(); } else { - printf_verbose("sslMethod = TLSv1_method()\n"); - printf_verbose("If server doesn't support TLSv1.0, manually specify TLS version\n"); - sslMethod = TLSv1_method(); + printf_verbose("sslMethod = TLS_method()\n"); + sslMethod = TLS_method(); } options->ctx = new_CTX(sslMethod); if (options->ctx != NULL) @@ -2608,9 +2607,8 @@ int showCertificate(struct sslCheckOptions *options) } #endif else { - printf_verbose("sslMethod = TLSv1_method()\n"); - printf_verbose("If server doesn't support TLSv1.0, manually specificy TLS version\n"); - sslMethod = TLSv1_method(); + printf_verbose("sslMethod = TLS_method()\n"); + sslMethod = TLS_method(); } options->ctx = new_CTX(sslMethod); if (options->ctx != NULL) @@ -3059,9 +3057,8 @@ int showTrustedCAs(struct sslCheckOptions *options) } #endif else { - printf_verbose("sslMethod = TLSv1_method()\n"); - printf_verbose("If server doesn't support TLSv1.0, manually specificy TLS version\n"); - sslMethod = TLSv1_method(); + printf_verbose("sslMethod = TLS_method()\n"); + sslMethod = TLS_method(); } options->ctx = new_CTX(sslMethod); if (options->ctx != NULL) From 1a11d0c0b5a9cf2b55108c21b367dfc74906eea6 Mon Sep 17 00:00:00 2001 From: rbsec Date: Sat, 22 Feb 2020 11:05:55 +0000 Subject: [PATCH 50/52] Update readme --- README.md | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 33713b7..7a8a549 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,24 @@ -# Beta Branch +# sslscan2 -This is a beta branch for the major rewrite by @jtesta to add in TLSv1.3 support (as well as other features). +An alpha build of sslscan 2 has been merged into master. If you want the old code, +the tag [1.11.11-rbsec](https://github.com/rbsec/sslscan/tree/1.11.11-rbsec) was the last release in that branch. -There may be bugs and other issues. Any feedback is greatly appreciated. +The main changes in sslscan2 is a major rewrite of the backend scanning code, +which means that it is no longer reliant on the version of OpenSSL for many checks. +This means that it is possible to support legacy protocols (SSLv2 and SSLv3), as well +as supporting TLSv1.3 - regardless of the version of OpenSSL that it has been compiled against. + +This has been made possible largely by the work of [jtesta](https://github.com/jtesta), who has been +responsible for most of the backend rewrite. + +Other key changes include: + +* Enumeration of server key exchange groups. +* Enumeration of server signature algorithms. +* SSLv2 and SSLv3 protocol support it scanned, but individual ciphers are not. +* A test suite is included using Docker, to verify that sslscan is functionality correctly. + +There are likely to be bugs in this version, so please report any that you encounter. # README From 38639da2e4bc59f9f4c2564e28e94bed464a084d Mon Sep 17 00:00:00 2001 From: rbsec Date: Sat, 22 Feb 2020 11:08:14 +0000 Subject: [PATCH 51/52] Update changelog --- Changelog | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Changelog b/Changelog index bc94b58..051cfef 100644 --- a/Changelog +++ b/Changelog @@ -1,6 +1,18 @@ Changelog ========= +Version: 2.0.0-alpha1 +Date : 22/02/2020 +Author : rbsec +Changes: The following are a list of changes + > Major rewrite of backend scanning code. + > Support for additional cipher suites. + > Support for TLSv1.3 + > Support for SSLv2 and SSLv3 protocol detection regardless of + OpenSSL. + > Checks for server key exchange groups. + > Checks for server signature algorithms. + Version: 1.11.13 Date : 24/03/2019 Author : rbsec From 6c18eb411aca4b802075dab99929b3f2ff143e90 Mon Sep 17 00:00:00 2001 From: rbsec Date: Sat, 22 Feb 2020 11:09:33 +0000 Subject: [PATCH 52/52] Fix TLSv1.3 not enabled output --- sslscan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sslscan.c b/sslscan.c index 03676b1..5f210d4 100644 --- a/sslscan.c +++ b/sslscan.c @@ -3388,7 +3388,7 @@ int testHost(struct sslCheckOptions *options) printf("TLSv1.3 %senabled%s\n", COL_GREEN, RESET); printf_xml(" \n"); } else { - printf("TLSv1.3 is not enabled\n"); + printf("TLSv1.3 not enabled\n"); printf_xml(" \n"); } }