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;