diff --git a/sslscan.c b/sslscan.c index 858f6c5..952ab60 100644 --- a/sslscan.c +++ b/sslscan.c @@ -2814,186 +2814,204 @@ int showCertificate(struct sslCheckOptions *options) BIO_set_fp(fileBIO, options->xmlOutput, BIO_NOCLOSE); } - // Get Certificate... - printf("\n %sSSL Certificate:%s\n", COL_BLUE, RESET); - printf_xml(" \n"); - x509Cert = SSL_get_peer_certificate(ssl); - if (x509Cert != NULL) - { + // Get certificate(s) chain + STACK_OF(X509) *certificatesChain; - // Print a base64 blob version of the cert - printf(" Certificate blob:\n"); - PEM_write_bio_X509(stdoutBIO,x509Cert); - if (options->xmlOutput) - { - printf_xml(" \n"); - PEM_write_bio_X509(fileBIO,x509Cert); - printf_xml(" \n"); - } + if (options->showCertificates == true) + { + certificatesChain = SSL_get_peer_cert_chain(ssl); + } + else + { + X509 *peerCertificate = SSL_get_peer_certificate(ssl); + certificatesChain = sk_X509_new_null(); + sk_X509_push(certificatesChain, peerCertificate); + } - //SSL_set_verify(ssl, SSL_VERIFY_NONE|SSL_VERIFY_CLIENT_ONCE, NULL); + for (int cert_index = 0; cert_index < sk_X509_num(certificatesChain); cert_index++) + { + // Get Certificate... + printf("\n %sSSL Certificate: %s\n", COL_BLUE, RESET); + printf_xml(" \n"); - //X509_print_ex(bp, x509Cert, 0, 0); + x509Cert = sk_X509_value(certificatesChain, cert_index); - // Cert Version - if (!(X509_FLAG_COMPAT & X509_FLAG_NO_VERSION)) + if (x509Cert != NULL) { - tempLong = X509_get_version(x509Cert); - printf(" Version: %lu\n", tempLong); - printf_xml(" %lu\n", tempLong); - } - // Cert Serial No. - Code adapted from OpenSSL's crypto/asn1/t_x509.c - if (!(X509_FLAG_COMPAT & X509_FLAG_NO_SERIAL)) - { - ASN1_INTEGER *bs; - BIO *bp; - BIO *xml_bp; - bp = BIO_new_fp(stdout, BIO_NOCLOSE); + // Print a base64 blob version of the cert + printf(" Certificate blob:\n"); + PEM_write_bio_X509(stdoutBIO,x509Cert); if (options->xmlOutput) - xml_bp = BIO_new_fp(options->xmlOutput, BIO_NOCLOSE); - long l; - int i; - const char *neg; - bs=X509_get_serialNumber(x509Cert); + { + printf_xml(" \n"); + PEM_write_bio_X509(fileBIO,x509Cert); + printf_xml(" \n"); + } + + // SSL_set_verify(ssl, SSL_VERIFY_NONE|SSL_VERIFY_CLIENT_ONCE, NULL); - if (BIO_write(bp," Serial Number:",18) <= 0) - return(1); + // X509_print_ex(bp, x509Cert, 0, 0); - if (bs->length <= 4) + // Cert Version + if (!(X509_FLAG_COMPAT & X509_FLAG_NO_VERSION)) { - l=ASN1_INTEGER_get(bs); - if (l < 0) - { - l= -l; - neg="-"; - } - else - neg=""; - if (BIO_printf(bp," %s%lu (%s0x%lx)\n",neg,l,neg,l) <= 0) - return(1); - if (options->xmlOutput) - if (BIO_printf(xml_bp," %s%lu (%s0x%lx)\n",neg,l,neg,l) <= 0) - return(1); + tempLong = X509_get_version(x509Cert); + printf(" Version: %lu\n", tempLong); + printf_xml(" %lu\n", tempLong); } - else + + // Cert Serial No. - Code adapted from OpenSSL's crypto/asn1/t_x509.c + if (!(X509_FLAG_COMPAT & X509_FLAG_NO_SERIAL)) { - neg=(bs->type == V_ASN1_NEG_INTEGER)?" (Negative)":""; - if (BIO_printf(bp,"%1s%s","",neg) <= 0) + ASN1_INTEGER *bs; + BIO *bp; + BIO *xml_bp; + bp = BIO_new_fp(stdout, BIO_NOCLOSE); + if (options->xmlOutput) + xml_bp = BIO_new_fp(options->xmlOutput, BIO_NOCLOSE); + long l; + int i; + const char *neg; + bs=X509_get_serialNumber(x509Cert); + + if (BIO_write(bp," Serial Number:",18) <= 0) return(1); - if (options->xmlOutput) - if (BIO_printf(xml_bp," ") <= 0) + if (bs->length <= 4) + { + l=ASN1_INTEGER_get(bs); + if (l < 0) + { + l= -l; + neg="-"; + } + else + neg=""; + if (BIO_printf(bp," %s%lu (%s0x%lx)\n",neg,l,neg,l) <= 0) return(1); - - for (i=0; ilength; i++) + if (options->xmlOutput) + if (BIO_printf(xml_bp," %s%lu (%s0x%lx)\n",neg,l,neg,l) <= 0) + return(1); + } + else { - if (BIO_printf(bp,"%02x%c",bs->data[i], - ((i+1 == bs->length)?'\n':':')) <= 0) + neg=(bs->type == V_ASN1_NEG_INTEGER)?" (Negative)":""; + if (BIO_printf(bp,"%1s%s","",neg) <= 0) return(1); - if (options->xmlOutput) { - if (i+1 == bs->length) - { - if (BIO_printf(xml_bp,"%02x",bs->data[i]) <= 0) - return(1); - } - else - { - if (BIO_printf(xml_bp,"%02x%c",bs->data[i], ':') <= 0) - return(1); + + if (options->xmlOutput) + if (BIO_printf(xml_bp," ") <= 0) + return(1); + + for (i=0; ilength; i++) + { + if (BIO_printf(bp,"%02x%c",bs->data[i], + ((i+1 == bs->length)?'\n':':')) <= 0) + return(1); + if (options->xmlOutput) { + if (i+1 == bs->length) + { + if (BIO_printf(xml_bp,"%02x",bs->data[i]) <= 0) + return(1); + } + else + { + if (BIO_printf(xml_bp,"%02x%c",bs->data[i], ':') <= 0) + return(1); + } } } - } - if (options->xmlOutput) - if (BIO_printf(xml_bp,"\n") <= 0) - return(1); + if (options->xmlOutput) + if (BIO_printf(xml_bp,"\n") <= 0) + return(1); + } + if(NULL != bp) + BIO_free(bp); + // We don't free the xml_bp because it will be used in the future } - if(NULL != bp) - BIO_free(bp); - // 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)) - { - 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) + // Signature Algo... + if (!(X509_FLAG_COMPAT & X509_FLAG_NO_SIGNAME)) { - printf_xml(" "); - X509_signature_print(fileBIO, X509_get0_tbs_sigalg(x509Cert), NULL); - printf_xml("\n"); + 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(" "); + X509_signature_print(fileBIO, X509_get0_tbs_sigalg(x509Cert), NULL); + printf_xml("\n"); + } } - } - - // SSL Certificate Issuer... - if (!(X509_FLAG_COMPAT & X509_FLAG_NO_ISSUER)) - { - X509_NAME_oneline(X509_get_issuer_name(x509Cert), buffer, sizeof(buffer) - 1); - printf(" Issuer: %s\n", buffer); - printf_xml(" \n", buffer); - } - // Validity... - if (!(X509_FLAG_COMPAT & X509_FLAG_NO_VALIDITY)) - { - printf(" Not valid before: "); - ASN1_TIME_print(stdoutBIO, X509_get_notBefore(x509Cert)); - if (options->xmlOutput) + // SSL Certificate Issuer... + if (!(X509_FLAG_COMPAT & X509_FLAG_NO_ISSUER)) { - printf_xml(" "); - ASN1_TIME_print(fileBIO, X509_get_notBefore(x509Cert)); - printf_xml("\n"); + X509_NAME_oneline(X509_get_issuer_name(x509Cert), buffer, sizeof(buffer) - 1); + printf(" Issuer: %s\n", buffer); + printf_xml(" \n", buffer); } - printf("\n Not valid after: "); - ASN1_TIME_print(stdoutBIO, X509_get_notAfter(x509Cert)); - printf("\n"); - if (options->xmlOutput) - { - printf_xml(" "); - ASN1_TIME_print(fileBIO, X509_get_notAfter(x509Cert)); - printf_xml("\n"); - } - } - // SSL Certificate Subject... - if (!(X509_FLAG_COMPAT & X509_FLAG_NO_SUBJECT)) - { - X509_NAME_oneline(X509_get_subject_name(x509Cert), buffer, sizeof(buffer) - 1); - printf(" Subject: %s\n", buffer); - printf_xml(" \n", buffer); - } - - // Public Key Algo... - if (!(X509_FLAG_COMPAT & X509_FLAG_NO_PUBKEY)) - { - printf(" Public Key Algorithm: "); - ASN1_OBJECT *xpoid = NULL; - i2a_ASN1_OBJECT(stdoutBIO, xpoid); - printf("\n"); - if (options->xmlOutput) + // Validity... + if (!(X509_FLAG_COMPAT & X509_FLAG_NO_VALIDITY)) { - printf_xml(" "); - i2a_ASN1_OBJECT(fileBIO, xpoid); - printf_xml("\n"); + printf(" Not valid before: "); + ASN1_TIME_print(stdoutBIO, X509_get_notBefore(x509Cert)); + if (options->xmlOutput) + { + printf_xml(" "); + ASN1_TIME_print(fileBIO, X509_get_notBefore(x509Cert)); + printf_xml("\n"); + } + printf("\n Not valid after: "); + ASN1_TIME_print(stdoutBIO, X509_get_notAfter(x509Cert)); + printf("\n"); + if (options->xmlOutput) + { + printf_xml(" "); + ASN1_TIME_print(fileBIO, X509_get_notAfter(x509Cert)); + printf_xml("\n"); + } } - // Public Key... - publicKey = X509_get_pubkey(x509Cert); - if (publicKey == NULL) + // SSL Certificate Subject... + if (!(X509_FLAG_COMPAT & X509_FLAG_NO_SUBJECT)) { - printf(" Public Key: Could not load\n"); - printf_xml(" \n"); + X509_NAME_oneline(X509_get_subject_name(x509Cert), buffer, sizeof(buffer) - 1); + printf(" Subject: %s\n", buffer); + printf_xml(" \n", buffer); } - else + + // Public Key Algo... + if (!(X509_FLAG_COMPAT & X509_FLAG_NO_PUBKEY)) { - switch (EVP_PKEY_id(publicKey)) + printf(" Public Key Algorithm: "); + ASN1_OBJECT *xpoid = NULL; + i2a_ASN1_OBJECT(stdoutBIO, xpoid); + printf("\n"); + if (options->xmlOutput) + { + printf_xml(" "); + i2a_ASN1_OBJECT(fileBIO, xpoid); + printf_xml("\n"); + } + + // Public Key... + publicKey = X509_get_pubkey(x509Cert); + if (publicKey == NULL) { + printf(" Public Key: Could not load\n"); + printf_xml(" \n"); + } + else + { + switch (EVP_PKEY_id(publicKey)) + { case EVP_PKEY_RSA: if (EVP_PKEY_get1_RSA(publicKey)!=NULL) { @@ -3049,77 +3067,79 @@ int showCertificate(struct sslCheckOptions *options) printf(" Public Key: Unknown\n"); printf_xml(" \n"); break; - } + } - EVP_PKEY_free(publicKey); + EVP_PKEY_free(publicKey); + } } - } - // X509 v3... - if (!(X509_FLAG_COMPAT & X509_FLAG_NO_EXTENSIONS)) - { - if (sk_X509_EXTENSION_num(X509_get0_extensions(x509Cert)) > 0) + // X509 v3... + if (!(X509_FLAG_COMPAT & X509_FLAG_NO_EXTENSIONS)) { - printf(" X509v3 Extensions:\n"); - printf_xml(" \n"); - for (tempInt = 0; tempInt < sk_X509_EXTENSION_num(X509_get0_extensions(x509Cert)); tempInt++) + if (sk_X509_EXTENSION_num(X509_get0_extensions(x509Cert)) > 0) { - // Get Extension... - extension = sk_X509_EXTENSION_value(X509_get0_extensions(x509Cert), tempInt); - - // Print Extension name... - printf(" "); - asn1Object = X509_EXTENSION_get_object(extension); - i2a_ASN1_OBJECT(stdoutBIO, asn1Object); - tempInt2 = X509_EXTENSION_get_critical(extension); - BIO_printf(stdoutBIO, ": %s\n", tempInt2 ? "critical" : ""); - if (options->xmlOutput) + printf(" X509v3 Extensions:\n"); + printf_xml(" \n"); + for (tempInt = 0; tempInt < sk_X509_EXTENSION_num(X509_get0_extensions(x509Cert)); tempInt++) { - printf_xml(" xmlOutput) + { + printf_xml(" xmlOutput) - { - if (!X509V3_EXT_print(fileBIO, extension, X509_FLAG_COMPAT, 0)) - ASN1_STRING_print(stdoutBIO, X509_EXTENSION_get_data(extension)); - printf_xml("]]>\n"); + // Print Extension value... + if (!X509V3_EXT_print(stdoutBIO, extension, X509_FLAG_COMPAT, 8)) + { + printf(" "); + ASN1_STRING_print(stdoutBIO, X509_EXTENSION_get_data(extension)); + } + if (options->xmlOutput) + { + if (!X509V3_EXT_print(fileBIO, extension, X509_FLAG_COMPAT, 0)) + ASN1_STRING_print(stdoutBIO, X509_EXTENSION_get_data(extension)); + printf_xml("]]>\n"); + } + printf("\n"); } - printf("\n"); + printf_xml(" \n"); } - printf_xml(" \n"); } - } - // Verify Certificate... - printf(" Verify Certificate:\n"); - verifyError = SSL_get_verify_result(ssl); - if (verifyError == X509_V_OK) - { - printf(" Certificate passed verification\n"); + // Verify Certificate... + printf(" Verify m:\n"); + verifyError = SSL_get_verify_result(ssl); + if (verifyError == X509_V_OK) + { + printf(" Certificate passed verification\n"); + } + else + { + printf(" %s\n", X509_verify_cert_error_string(verifyError)); + } + + // Free X509 Certificate... + X509_free(x509Cert); } + else { - printf(" %s\n", X509_verify_cert_error_string(verifyError)); + printf(" Unable to parse certificate\n"); } - // Free X509 Certificate... - X509_free(x509Cert); - } - - else { - printf(" Unable to parse certificate\n"); + printf_xml(" \n"); } - printf_xml(" \n"); - // Free BIO BIO_free(stdoutBIO); if (options->xmlOutput) @@ -3710,8 +3730,9 @@ int testHost(struct sslCheckOptions *options) if (status == true && (options->showCertificate == true || options->checkCertificate == true)) { printf_xml(" \n"); - // Full certificate details (--show-certificates) - if (status == true && options->showCertificate == true) + + // Full certificate details + if (status == true && (options->showCertificate == true || options->showCertificates == true)) { status = showCertificate(options); } @@ -3874,10 +3895,14 @@ int main(int argc, char *argv[]) options->targets = argLoop; } - // Show certificate + // Show certificate (only one) else if (strcmp("--show-certificate", argv[argLoop]) == 0) options->showCertificate = true; + // Show certificates (all) + else if (strcmp("--show-certificates", argv[argLoop]) == 0) + options->showCertificates = true; + // Don't check certificate strength else if (strcmp("--no-check-certificate", argv[argLoop]) == 0) options->checkCertificate = false; @@ -4239,6 +4264,7 @@ int main(int argc, char *argv[]) printf(" %s--ipv6, -6%s Only use IPv6\n", COL_GREEN, RESET); printf("\n"); printf(" %s--show-certificate%s Show full certificate information\n", COL_GREEN, RESET); + printf(" %s--show-certificates%s Show chain full certificates information\n", COL_GREEN, RESET); printf(" %s--show-client-cas%s Show trusted CAs for TLS client auth\n", COL_GREEN, RESET); printf(" %s--no-check-certificate%s Don't warn about weak certificate algorithm or keys\n", COL_GREEN, RESET); printf(" %s--ocsp%s Request OCSP response from server\n", COL_GREEN, RESET); diff --git a/sslscan.h b/sslscan.h index 318ef2b..a64e2e6 100644 --- a/sslscan.h +++ b/sslscan.h @@ -151,6 +151,7 @@ struct sslCheckOptions char addrstr[INET6_ADDRSTRLEN]; int port; int showCertificate; + int showCertificates; int checkCertificate; int showTrustedCAs; int showClientCiphers;