Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package sslscan for openSUSE:Factory checked in at 2022-08-02 22:09:36 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/sslscan (Old) and /work/SRC/openSUSE:Factory/.sslscan.new.1533 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "sslscan" Tue Aug 2 22:09:36 2022 rev:12 rq:992247 version:2.0.15 Changes: -------- --- /work/SRC/openSUSE:Factory/sslscan/sslscan.changes 2022-03-28 17:01:48.929071613 +0200 +++ /work/SRC/openSUSE:Factory/.sslscan.new.1533/sslscan.changes 2022-08-02 22:10:28.353993995 +0200 @@ -1,0 +2,8 @@ +Tue Aug 2 11:31:57 UTC 2022 - Dirk M??ller <[email protected]> + +- update to 2.0.15: + * Obtain certificate info even if we can't connect properly + * Strip out https:// from lines in a target file + * Fix TLSv1.3 detection against Server 2022 (credit jtesta) + +------------------------------------------------------------------- @@ -5 +13 @@ - > Add <not-yet-valid> XML element (credit lucacapacci) + * Add <not-yet-valid> XML element (credit lucacapacci) Old: ---- sslscan-2.0.12.tar.gz New: ---- sslscan-2.0.15.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ sslscan.spec ++++++ --- /var/tmp/diff_new_pack.Zq62A4/_old 2022-08-02 22:10:28.789995252 +0200 +++ /var/tmp/diff_new_pack.Zq62A4/_new 2022-08-02 22:10:28.793995264 +0200 @@ -17,7 +17,7 @@ Name: sslscan -Version: 2.0.12 +Version: 2.0.15 Release: 0 Summary: SSL cipher scanning tool License: SUSE-GPL-3.0+-with-openssl-exception ++++++ sslscan-2.0.12.tar.gz -> sslscan-2.0.15.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sslscan-2.0.12/.github/workflows/ci.yml new/sslscan-2.0.15/.github/workflows/ci.yml --- old/sslscan-2.0.12/.github/workflows/ci.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/sslscan-2.0.15/.github/workflows/ci.yml 2022-07-03 17:42:37.000000000 +0200 @@ -0,0 +1,30 @@ +name: ci + +on: push + +jobs: + build: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + cc: [clang, gcc] + steps: + - uses: actions/checkout@v2 + - name: build with ${{ matrix.cc }} + run: | + make sslscan + make static + env: + CC: ${{ matrix.cc }} + build_mingw: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: install mingw-w64 + run: | + sudo apt-get update -qq + sudo apt-get install -qq mingw-w64 + - name: build with mingw-w64 + run: | + make -f Makefile.mingw diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sslscan-2.0.12/.travis.yml new/sslscan-2.0.15/.travis.yml --- old/sslscan-2.0.12/.travis.yml 2022-02-23 17:11:27.000000000 +0100 +++ new/sslscan-2.0.15/.travis.yml 1970-01-01 01:00:00.000000000 +0100 @@ -1,14 +0,0 @@ -sudo: required -dist: bionic -language: c - -before_install: - - sudo apt-get update -qq - - sudo apt-get install -qq mingw-w64 - -script: - - make sslscan CC=clang - - make sslscan CC=gcc - - make static CC=clang - - make static CC=gcc - - make -f Makefile.mingw diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sslscan-2.0.12/Changelog new/sslscan-2.0.15/Changelog --- old/sslscan-2.0.12/Changelog 2022-02-23 17:11:27.000000000 +0100 +++ new/sslscan-2.0.15/Changelog 2022-07-03 17:42:37.000000000 +0200 @@ -1,5 +1,23 @@ Changelog ========= +Version: 2.0.15 +Date : 03/07/2022 +Author : rbsec <[email protected]> +Changes: The following are a list of changes + > Obtain certificate info even if we can't connect properly + +Version: 2.0.14 +Date : 23/06/2022 +Author : rbsec <[email protected]> +Changes: The following are a list of changes + > Strip out https:// from lines in a target file + +Version: 2.0.13 +Date : 03/04/2022 +Author : rbsec <[email protected]> +Changes: The following are a list of changes + > Fix TLSv1.3 detection against Server 2022 (credit jtesta) + Version: 2.0.12 Date : 23/02/2022 Author : rbsec <[email protected]> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sslscan-2.0.12/README.md new/sslscan-2.0.15/README.md --- old/sslscan-2.0.12/README.md 2022-02-23 17:11:27.000000000 +0100 +++ new/sslscan-2.0.15/README.md 2022-07-03 17:42:37.000000000 +0200 @@ -28,7 +28,7 @@ # README -[](https://travis-ci.org/rbsec/sslscan) +[](https://github.com/rbsec/sslscan/actions/workflows/ci.yml) This is a fork of ioerror's version of sslscan (the original readme of which is included below). Key changes are as follows: @@ -39,7 +39,7 @@ * Highlight PFS+GCM ciphers as good in output. * Highlight NULL (0 bit), weak (<40 bit) and medium (40 < n <= 56) ciphers in output. * Highlight anonymous (ADH and AECDH) ciphers in output (purple). -* Hide certificate information by default (display with `--get-certificate`). +* Hide certificate information by default (display with `--show-certificate`). * Hide rejected ciphers by default (display with `--failed`). * Added TLSv1.1, TLSv1.2 and TLSv1.3 support. * Supports IPv6 (can be forced with `--ipv6`). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sslscan-2.0.12/sslscan.c new/sslscan-2.0.15/sslscan.c --- old/sslscan-2.0.12/sslscan.c 2022-02-23 17:11:27.000000000 +0100 +++ new/sslscan-2.0.15/sslscan.c 2022-07-03 17:42:37.000000000 +0200 @@ -1985,7 +1985,6 @@ // Report certificate weaknesses (key length and signing algorithm) int checkCertificate(struct sslCheckOptions *options, const SSL_METHOD *sslMethod) { - int cipherStatus = 0; int status = true; int socketDescriptor = 0; int keyBits; @@ -2043,120 +2042,118 @@ #endif // Connect SSL over socket - cipherStatus = SSL_connect(ssl); - if (cipherStatus == 1) + SSL_connect(ssl); + // Setup BIO's + if (!xml_to_stdout) { + stdoutBIO = BIO_new(BIO_s_file()); + BIO_set_fp(stdoutBIO, stdout, BIO_NOCLOSE); + } + if (options->xmlOutput) { - // Setup BIO's - if (!xml_to_stdout) { - stdoutBIO = BIO_new(BIO_s_file()); - BIO_set_fp(stdoutBIO, stdout, BIO_NOCLOSE); - } - if (options->xmlOutput) - { - fileBIO = BIO_new(BIO_s_file()); - BIO_set_fp(fileBIO, options->xmlOutput, BIO_NOCLOSE); - } + fileBIO = BIO_new(BIO_s_file()); + BIO_set_fp(fileBIO, options->xmlOutput, BIO_NOCLOSE); + } - // Get Certificate... + // Get Certificate... + x509Cert = SSL_get_peer_certificate(ssl); + if (x509Cert != NULL) + { printf("\n %sSSL Certificate:%s\n", COL_BLUE, RESET); printf_xml(" <certificate type=\"short\">\n"); - x509Cert = SSL_get_peer_certificate(ssl); - if (x509Cert != NULL) + // Cert Serial No. - Code adapted from OpenSSL's crypto/asn1/t_x509.c + if (!(X509_FLAG_COMPAT & X509_FLAG_NO_SERIAL)) { - // Cert Serial No. - Code adapted from OpenSSL's crypto/asn1/t_x509.c - if (!(X509_FLAG_COMPAT & X509_FLAG_NO_SERIAL)) - { - BIO *bp; - bp = BIO_new_fp(stdout, BIO_NOCLOSE); - if (options->xmlOutput) + BIO *bp; + bp = BIO_new_fp(stdout, BIO_NOCLOSE); + if (options->xmlOutput) if(NULL != bp) BIO_free(bp); - // We don't free the xml_bp because it will be used in the future - } + // We don't free the xml_bp because it will be used in the future + } - // Signature Algo... - if (!(X509_FLAG_COMPAT & X509_FLAG_NO_SIGNAME)) + // Signature Algo... + if (!(X509_FLAG_COMPAT & X509_FLAG_NO_SIGNAME)) + { + printf("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("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("%s%s%s\n", COL_RED, certAlgorithm, RESET); - } - else if (strstr(certAlgorithm, "sha512") || strstr(certAlgorithm, "sha256")) - { - printf("%s%s%s\n", COL_GREEN, certAlgorithm, RESET); - } - else - { - printf("%s\n", certAlgorithm); - } + printf("%s%s%s\n", COL_RED, certAlgorithm, RESET); + } + else if (strstr(certAlgorithm, "sha512") || strstr(certAlgorithm, "sha256")) + { + printf("%s%s%s\n", COL_GREEN, certAlgorithm, RESET); + } + else + { + printf("%s\n", certAlgorithm); + } - if (options->xmlOutput) - { - printf_xml(" <signature-algorithm>%s</signature-algorithm>\n", certAlgorithm); - } + if (options->xmlOutput) + { + printf_xml(" <signature-algorithm>%s</signature-algorithm>\n", certAlgorithm); } + } - // Public Key... - if (!(X509_FLAG_COMPAT & X509_FLAG_NO_PUBKEY)) + // Public Key... + if (!(X509_FLAG_COMPAT & X509_FLAG_NO_PUBKEY)) + { + publicKey = X509_get_pubkey(x509Cert); + if (publicKey == NULL) { - publicKey = X509_get_pubkey(x509Cert); - if (publicKey == NULL) - { - printf("Public Key: Could not load\n"); - printf_xml(" <pk error=\"true\" />\n"); - } - else + printf("Public Key: Could not load\n"); + printf_xml(" <pk error=\"true\" />\n"); + } + else + { + keyBits=EVP_PKEY_bits(publicKey); + switch (EVP_PKEY_id(publicKey)) { - keyBits=EVP_PKEY_bits(publicKey); - switch (EVP_PKEY_id(publicKey)) - { - case EVP_PKEY_RSA: - if (EVP_PKEY_get1_RSA(publicKey)!=NULL) - { - if (keyBits < 2048 ) - { - printf("RSA Key Strength: %s%d%s\n", COL_RED, keyBits, RESET); - } - else if (keyBits >= 3072 ) - { - printf("RSA Key Strength: %s%d%s\n", COL_GREEN, keyBits, RESET); - } - else - { - printf("RSA Key Strength: %d\n", keyBits); - } - - printf_xml(" <pk error=\"false\" type=\"RSA\" bits=\"%d\" />\n", keyBits); - } - else + case EVP_PKEY_RSA: + if (EVP_PKEY_get1_RSA(publicKey)!=NULL) + { + if (keyBits < 2048 ) { - printf(" RSA Public Key: NULL\n"); + printf("RSA Key Strength: %s%d%s\n", COL_RED, keyBits, RESET); } - printf("\n"); - break; - case EVP_PKEY_DSA: - if (EVP_PKEY_get1_DSA(publicKey)!=NULL) + else if (keyBits >= 3072 ) { - // TODO - display key strength - printf_xml(" <pk error=\"false\" type=\"DSA\" />\n"); - /* DSA_print(stdoutBIO, publicKey->pkey.dsa, 6); */ + printf("RSA Key Strength: %s%d%s\n", COL_GREEN, keyBits, RESET); } else { - printf(" DSA Public Key: NULL\n"); + printf("RSA Key Strength: %d\n", keyBits); } - break; - case EVP_PKEY_EC: + + printf_xml(" <pk error=\"false\" type=\"RSA\" bits=\"%d\" />\n", keyBits); + } + else + { + printf(" RSA Public Key: NULL\n"); + } + printf("\n"); + break; + case EVP_PKEY_DSA: + if (EVP_PKEY_get1_DSA(publicKey)!=NULL) + { + // TODO - display key strength + printf_xml(" <pk error=\"false\" type=\"DSA\" />\n"); + /* DSA_print(stdoutBIO, publicKey->pkey.dsa, 6); */ + } + else + { + printf(" DSA Public Key: NULL\n"); + } + break; + case EVP_PKEY_EC: + { + EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(publicKey); + if (ec_key != NULL) { - EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(publicKey); - if (ec_key != NULL) - { // We divide by two to get the symmetric key strength equivalent; this // ensures consistency with the Server Key Exchange Group section. int keyBits = EVP_PKEY_bits(publicKey) / 2; @@ -2165,222 +2162,221 @@ if (keyBits < 112) - color = COL_RED; + color = COL_RED; else if (keyBits < 128) - color = COL_YELLOW; + color = COL_YELLOW; printf("ECC Curve Name: %s\n", ec_group_name); printf("ECC Key Strength: %s%d%s\n\n", color, keyBits, RESET); printf_xml(" <pk error=\"false\" type=\"EC\" curve_name=\"%s\" bits=\"%d\" />\n", ec_group_name, keyBits); EC_KEY_free(ec_key); ec_key = NULL; - } - else - printf(" EC Public Key: NULL\n"); } - break; - default: - printf(" Public Key: Unknown\n"); - printf_xml(" <pk error=\"true\" type=\"unknown\" />\n"); - break; - } - - EVP_PKEY_free(publicKey); + else + printf(" EC Public Key: NULL\n"); + } + break; + default: + printf(" Public Key: Unknown\n"); + printf_xml(" <pk error=\"true\" type=\"unknown\" />\n"); + break; } - } - // SSL Certificate Issuer... - if (!(X509_FLAG_COMPAT & X509_FLAG_NO_ISSUER)) - { - int cnindex; - X509_NAME *subj; - X509_NAME_ENTRY *e; - ASN1_STRING *d; - const char *subject; - const char *issuer; - - // Get SSL cert CN - cnindex = -1; - subj = X509_get_subject_name(x509Cert); - cnindex = X509_NAME_get_index_by_NID(subj, NID_commonName, cnindex); + EVP_PKEY_free(publicKey); + } + } - // SSL cert doesn't have a CN, so just print whole thing - if (cnindex == -1) - { - subject = (char *) X509_NAME_oneline(X509_get_subject_name(x509Cert), NULL, 0); - printf("Subject: %s\n", subject); - printf_xml(" <subject><![CDATA[%s]]></subject>\n", subject); + // SSL Certificate Issuer... + if (!(X509_FLAG_COMPAT & X509_FLAG_NO_ISSUER)) + { + int cnindex; + X509_NAME *subj; + X509_NAME_ENTRY *e; + ASN1_STRING *d; + const char *subject; + const char *issuer; + + // Get SSL cert CN + cnindex = -1; + subj = X509_get_subject_name(x509Cert); + cnindex = X509_NAME_get_index_by_NID(subj, NID_commonName, cnindex); + + // SSL cert doesn't have a CN, so just print whole thing + if (cnindex == -1) + { + subject = (char *) X509_NAME_oneline(X509_get_subject_name(x509Cert), NULL, 0); + printf("Subject: %s\n", subject); + printf_xml(" <subject><![CDATA[%s]]></subject>\n", subject); - } - else - { - e = X509_NAME_get_entry(subj, cnindex); - d = X509_NAME_ENTRY_get_data(e); - subject = (char *) ASN1_STRING_data(d); - printf("Subject: %s\n", subject); - printf_xml(" <subject><![CDATA[%s]]></subject>\n", subject); - } + } + else + { + e = X509_NAME_get_entry(subj, cnindex); + d = X509_NAME_ENTRY_get_data(e); + subject = (char *) ASN1_STRING_data(d); + printf("Subject: %s\n", subject); + printf_xml(" <subject><![CDATA[%s]]></subject>\n", subject); + } - // Get certificate altnames if supported - if (!(X509_FLAG_COMPAT & X509_FLAG_NO_EXTENSIONS)) + // Get certificate altnames if supported + if (!(X509_FLAG_COMPAT & X509_FLAG_NO_EXTENSIONS)) + { + if (sk_X509_EXTENSION_num(X509_get0_extensions(x509Cert)) > 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) { - cnindex = X509_get_ext_by_NID (x509Cert, NID_subject_alt_name, -1); - if (cnindex != -1) - { - extension = X509v3_get_ext(X509_get0_extensions(x509Cert),cnindex); + extension = X509v3_get_ext(X509_get0_extensions(x509Cert),cnindex); - printf("Altnames: "); - if (!X509V3_EXT_print(stdoutBIO, extension, X509_FLAG_COMPAT, 0)) - { - ASN1_STRING_print(stdoutBIO, X509_EXTENSION_get_data(extension)); - } - if (options->xmlOutput) - { - printf_xml(" <altnames><![CDATA["); - if (!X509V3_EXT_print(fileBIO, extension, X509_FLAG_COMPAT, 0)) - ASN1_STRING_print(fileBIO, X509_EXTENSION_get_data(extension)); - } - printf_xml("]]></altnames>\n"); - printf("\n"); + printf("Altnames: "); + if (!X509V3_EXT_print(stdoutBIO, extension, X509_FLAG_COMPAT, 0)) + { + ASN1_STRING_print(stdoutBIO, X509_EXTENSION_get_data(extension)); + } + if (options->xmlOutput) + { + printf_xml(" <altnames><![CDATA["); + if (!X509V3_EXT_print(fileBIO, extension, X509_FLAG_COMPAT, 0)) + ASN1_STRING_print(fileBIO, X509_EXTENSION_get_data(extension)); } + printf_xml("]]></altnames>\n"); + printf("\n"); } } + } - // Get SSL cert issuer - cnindex = -1; - subj = X509_get_issuer_name(x509Cert); - cnindex = X509_NAME_get_index_by_NID(subj, NID_commonName, cnindex); + // Get SSL cert issuer + cnindex = -1; + subj = X509_get_issuer_name(x509Cert); + cnindex = X509_NAME_get_index_by_NID(subj, NID_commonName, cnindex); + + // Issuer cert doesn't have a CN, so just print whole thing + if (cnindex == -1) + { + char *issuer = X509_NAME_oneline(X509_get_issuer_name(x509Cert), NULL, 0); + char *color = ""; + int self_signed = 0; + + if ((subject != NULL) && (strcmp(subject, issuer) == 0)) { + color = COL_RED; + self_signed = 1; + } + printf("%sIssuer: %s%s", color, issuer, RESET); + printf_xml(" <issuer><![CDATA[%s]]></issuer>\n", issuer); - // Issuer cert doesn't have a CN, so just print whole thing - if (cnindex == -1) + if (self_signed) { + printf_xml(" <self-signed>true</self-signed>\n"); + } + else { + printf_xml(" <self-signed>false</self-signed>\n"); + } + } + else + { + e = X509_NAME_get_entry(subj, cnindex); + d = X509_NAME_ENTRY_get_data(e); + issuer = (char *) ASN1_STRING_data(d); + + // If issuer is same as hostname we scanned or is *, flag as self-signed + if ( + strcmp(issuer, options->host) == 0 + || strcmp(issuer, subject) == 0 + || strcmp(issuer, "*") == 0 + ) { - char *issuer = X509_NAME_oneline(X509_get_issuer_name(x509Cert), NULL, 0); - char *color = ""; - int self_signed = 0; - - if ((subject != NULL) && (strcmp(subject, issuer) == 0)) { - color = COL_RED; - self_signed = 1; - } - printf("%sIssuer: %s%s", color, issuer, RESET); + printf("Issuer: %s%s%s\n", COL_RED, issuer, RESET); printf_xml(" <issuer><![CDATA[%s]]></issuer>\n", issuer); + printf_xml(" <self-signed>true</self-signed>\n"); - if (self_signed) { - printf_xml(" <self-signed>true</self-signed>\n"); - } - else { - printf_xml(" <self-signed>false</self-signed>\n"); - } } else { - e = X509_NAME_get_entry(subj, cnindex); - d = X509_NAME_ENTRY_get_data(e); - issuer = (char *) ASN1_STRING_data(d); - - // If issuer is same as hostname we scanned or is *, flag as self-signed - if ( - strcmp(issuer, options->host) == 0 - || strcmp(issuer, subject) == 0 - || strcmp(issuer, "*") == 0 - ) - { - printf("Issuer: %s%s%s\n", COL_RED, issuer, RESET); - printf_xml(" <issuer><![CDATA[%s]]></issuer>\n", issuer); - printf_xml(" <self-signed>true</self-signed>\n"); - - } - else - { - printf("Issuer: %s\n", issuer); - printf_xml(" <issuer><![CDATA[%s]]></issuer>\n", issuer); - printf_xml(" <self-signed>false</self-signed>\n"); - } + printf("Issuer: %s\n", issuer); + printf_xml(" <issuer><![CDATA[%s]]></issuer>\n", issuer); + printf_xml(" <self-signed>false</self-signed>\n"); } } + } + + // Check for certificate expiration + time_t *ptime; + int timediff; + ptime = NULL; + + printf("\nNot valid before: "); + timediff = X509_cmp_time(X509_get_notBefore(x509Cert), ptime); + // Certificate isn't valid yet + if (timediff > 0) + { + printf("%s", COL_RED); + } + else + { + printf("%s", COL_GREEN); + } + ASN1_TIME_print(stdoutBIO, X509_get_notBefore(x509Cert)); + printf("%s", RESET); - // Check for certificate expiration - time_t *ptime; - int timediff; - ptime = NULL; - - printf("\nNot valid before: "); - timediff = X509_cmp_time(X509_get_notBefore(x509Cert), ptime); - // Certificate isn't valid yet + if (options->xmlOutput) { + printf_xml(" <not-valid-before>"); + ASN1_TIME_print(fileBIO, X509_get_notBefore(x509Cert)); + printf_xml("</not-valid-before>\n"); if (timediff > 0) { - printf("%s", COL_RED); + printf_xml(" <not-yet-valid>true</not-yet-valid>\n"); } else { - printf("%s", COL_GREEN); + printf_xml(" <not-yet-valid>false</not-yet-valid>\n"); } - ASN1_TIME_print(stdoutBIO, X509_get_notBefore(x509Cert)); - printf("%s", RESET); + } - if (options->xmlOutput) { - printf_xml(" <not-valid-before>"); - ASN1_TIME_print(fileBIO, X509_get_notBefore(x509Cert)); - printf_xml("</not-valid-before>\n"); - if (timediff > 0) - { - printf_xml(" <not-yet-valid>true</not-yet-valid>\n"); - } - else - { - printf_xml(" <not-yet-valid>false</not-yet-valid>\n"); - } - } - - printf("\nNot valid after: "); - timediff = X509_cmp_time(X509_get_notAfter(x509Cert), ptime); - // Certificate has expired + printf("\nNot valid after: "); + timediff = X509_cmp_time(X509_get_notAfter(x509Cert), ptime); + // Certificate has expired + if (timediff < 0) + { + printf("%s", COL_RED); + } + else + { + printf("%s", COL_GREEN); + } + ASN1_TIME_print(stdoutBIO, X509_get_notAfter(x509Cert)); + printf("%s", RESET); + if (options->xmlOutput) { + printf_xml(" <not-valid-after>"); + ASN1_TIME_print(fileBIO, X509_get_notAfter(x509Cert)); + printf_xml("</not-valid-after>\n"); if (timediff < 0) { - printf("%s", COL_RED); + printf_xml(" <expired>true</expired>\n"); } else { - printf("%s", COL_GREEN); - } - ASN1_TIME_print(stdoutBIO, X509_get_notAfter(x509Cert)); - printf("%s", RESET); - if (options->xmlOutput) { - printf_xml(" <not-valid-after>"); - ASN1_TIME_print(fileBIO, X509_get_notAfter(x509Cert)); - printf_xml("</not-valid-after>\n"); - if (timediff < 0) - { - printf_xml(" <expired>true</expired>\n"); - } - else - { - printf_xml(" <expired>false</expired>\n"); - } + printf_xml(" <expired>false</expired>\n"); } - printf("\n"); - - // Free X509 Certificate... - X509_free(x509Cert); - // This is abusing status a bit, but means that we'll only get the cert once - status = false; } + printf("\n"); - else { - printf(" Unable to parse certificate\n"); - } + // Free X509 Certificate... + X509_free(x509Cert); + // This is abusing status a bit, but means that we'll only get the cert once + status = false; + } - printf_xml(" </certificate>\n"); + else { + printf(" Unable to parse certificate\n"); + } - // Free BIO - BIO_free(stdoutBIO); - if (options->xmlOutput) - BIO_free(fileBIO); + printf_xml(" </certificate>\n"); - // Disconnect SSL over socket - SSL_shutdown(ssl); - } + // Free BIO + BIO_free(stdoutBIO); + if (options->xmlOutput) + BIO_free(fileBIO); + + // Disconnect SSL over socket + SSL_shutdown(ssl); // Free SSL object FREE_SSL(ssl); } @@ -4345,6 +4341,12 @@ { if (strlen(line) != 0) { + // Strip https:// from the start of the hostname + if (strncmp(line, "https://", 8) == 0) + { + memmove(line, line + 8, (strlen(line) - 8)); + memset(line + (strlen(line) - 8), 0, 8); + } // Get host... tempInt = 0; while ((line[tempInt] != 0) && (line[tempInt] != ':')) @@ -4862,6 +4864,43 @@ } +/* Internal function. Use bs_append_x25519_pubkey() and bs_append_x448_pubkey() instead. */ +void __bs_append_xstar_pubkey(bs *b, unsigned int gen_x25519) { + unsigned char public_key[64] = {0}; /* X25519 requires 32 bytes minimum, and X448 requires 56 bytes minimum. */ + size_t public_key_len = sizeof(public_key); + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *pctx = NULL; + + + /* Create an X25519 or X448 key depending on which is requested. */ + if (gen_x25519) + pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL); + else + pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X448, NULL); + + /* Create the private and public keys, and append the raw public key to the byte string. */ + EVP_PKEY_keygen_init(pctx); + EVP_PKEY_keygen(pctx, &pkey); + EVP_PKEY_get_raw_public_key(pkey, public_key, &public_key_len); + bs_append_bytes(b, public_key, public_key_len); + + EVP_PKEY_free(pkey); pkey = NULL; + EVP_PKEY_CTX_free(pctx); pctx = NULL; +} + + +/* Generates a random x25519 public key and appends it to the byte string. */ +void bs_append_x25519_pubkey(bs *b) { + __bs_append_xstar_pubkey(b, 1); +} + + +/* Generates a random x448 public key and appends it to the byte string. */ +void bs_append_x448_pubkey(bs *b) { + __bs_append_xstar_pubkey(b, 0); +} + + /* 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; @@ -5165,12 +5204,8 @@ 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); - } + /* Append a random X25519 public key. */ + bs_append_x25519_pubkey(tls_extensions); /* Update the length of the extensions. */ tlsExtensionUpdateLength(tls_extensions); @@ -5438,7 +5473,7 @@ 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; + bs *client_hello = NULL, *ciphersuite_list = NULL, *tls_extensions = NULL, *tls_record = NULL, *key_exchange = NULL; struct group_key_exchange { uint16_t group_id; @@ -5453,9 +5488,11 @@ /* 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_UNUSED 0 #define NID_TYPE_ECDHE 1 /* For ECDHE curves (sec*, P-256/384-521) */ #define NID_TYPE_DHE 2 /* For ffdhe* */ +#define NID_TYPE_X25519 3 +#define NID_TYPE_X448 4 /* 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[] = { {0x0001, "sect163k1", 81, COL_RED, NID_sect163k1, NID_TYPE_ECDHE, 0}, @@ -5486,8 +5523,8 @@ {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}, + {0x001d, "x25519", 128, COL_GREEN, -1, NID_TYPE_X25519, 32}, + {0x001e, "x448", 224, COL_GREEN, -1, NID_TYPE_X448, 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}, @@ -5541,16 +5578,11 @@ 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) { + if (nid_type == NID_TYPE_X25519) + bs_append_x25519_pubkey(key_exchange); + else if (nid_type == NID_TYPE_X448) + bs_append_x448_pubkey(key_exchange); + else if (nid_type == NID_TYPE_ECDHE) { /* Generate the ECDHE key. */ EC_KEY *key = EC_KEY_new_by_curve_name(nid); @@ -5663,36 +5695,48 @@ } bs_free(&client_hello); - server_hello = getServerHello(s); + tls_record = getServerHello(s); /* This group is definitely not supported. */ - if (server_hello == NULL) { + if (tls_record == NULL) { CLOSE(s); continue; } - bs_free(&server_hello); - /* 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; - } + unsigned int handshake_type = 0; + unsigned int handshake_type_offset = 5; + uint32_t handshake_len = 0; - /* 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 */ + /* Loop through all the handshake protocols inside this TLS record. Some implementations only include one (such as OpenSSL), and others include several (such as Windows Server 2022). */ + while (tls_record != NULL) { + + handshake_type = bs_get_byte(tls_record, handshake_type_offset); + + /* Handshake type 12 is a Server Key Exchange. This may have the group information we need, so we can stop searching. */ + if (handshake_type == 12) { + break; + /* Handshake type 14 is a Server Hello Done. If we reach this before finding a Server Key Exchange, we know the server does not support this group. */ + } else if (handshake_type == 14) { bs_free(&tls_record); CLOSE(s); continue; } + + /* The handshake length is strangely only three bytes... */ + handshake_len = bs_get_byte(tls_record, handshake_type_offset + 1) << 16; + handshake_len |= bs_get_byte(tls_record, handshake_type_offset + 2) << 8; + handshake_len |= bs_get_byte(tls_record, handshake_type_offset + 3) << 0; + + /* If we processed all handshake messages in this TLS record, read the next record. */ + if (tls_record->len < handshake_len + handshake_type_offset) { + bs_free(&tls_record); + tls_record = getTLSHandshakeRecord(s); + handshake_type_offset = 5; + } else + handshake_type_offset += (handshake_len + 4); + } /* Error, so skip this group. */ @@ -5703,22 +5747,22 @@ } /* If this Server Key Exchange does not have a named_curve (3) field, skip this group. */ - if (bs_get_byte(tls_record, 9) != 3) { + if (bs_get_byte(tls_record, handshake_type_offset + 4) != 3) { bs_free(&tls_record); CLOSE(s); 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); + uint16_t server_group_id = bs_get_byte(tls_record, handshake_type_offset + 5) << 8 | bs_get_byte(tls_record, handshake_type_offset + 6); if (server_group_id != group_id) { bs_free(&tls_record); CLOSE(s); continue; } - - bs_free(&tls_record); } + + bs_free(&tls_record); CLOSE(s); if (!printed_header) { @@ -5743,7 +5787,7 @@ bs_free(&ciphersuite_list); bs_free(&tls_extensions); bs_free(&client_hello); - bs_free(&server_hello); + bs_free(&tls_record); return ret; }
