Skip to content

Commit 465ed4e

Browse files
authored
RFC: Experimental support for servers which require a client certificate
RFC: Experimental support for servers which require a client certificate (Fixes rbsec#119). Fix: Typo s/response/respond in "Some servers will fail to response to SSLv3 ciphers over STARTTLS" Fix: Logic error prevents show trusted CAs running with checkCertificate == true. RFC patch to enable scanning of servers which require a client certificate. How: Allow tests to continue in the event the SSL_connect() fails with certain "acceptable" errors . These are: SSL alert 40 (Handshake failure) SSL alert 46 (Certificate Unknown) SSL alert 42 (Bad Certificate) Testing is encouraged. Unfortunately I cannot provide any public test cases.
1 parent c742ad6 commit 465ed4e

File tree

2 files changed

+47
-13
lines changed

2 files changed

+47
-13
lines changed

sslscan.c

+46-13
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,10 @@ int testFallback(struct sslCheckOptions *options, const SSL_METHOD *sslMethod)
10131013

10141014
// Connect SSL over socket
10151015
connStatus = SSL_connect(ssl);
1016+
1017+
// We can't check for "acceptable" errors for "client cert required" here, since SSL Alert 40 (Handshake failure)
1018+
// can be reported for either client cert required, or downgrade failure. So it's not possible to distinguish
1019+
// between them.
10161020
if (connStatus)
10171021
{
10181022
if (!downgraded)
@@ -1062,8 +1066,8 @@ int testFallback(struct sslCheckOptions *options, const SSL_METHOD *sslMethod)
10621066
}
10631067
else
10641068
{
1065-
printf("%sConnection failed%s - unable to determine TLS Fallback SCSV support\n\n",
1066-
COL_YELLOW, RESET);
1069+
printf("%sConnection failed%s - unable to determine TLS Fallback SCSV support%s.\n\n",
1070+
COL_YELLOW, RESET, acceptableError() ? " - Server requires a client cert":"");
10671071
status = false;
10681072
}
10691073
}
@@ -1198,7 +1202,7 @@ int testRenegotiation(struct sslCheckOptions *options, const SSL_METHOD *sslMeth
11981202
}
11991203

12001204

1201-
if (cipherStatus == 1)
1205+
if (cipherStatus == 1 || acceptableError());
12021206
{
12031207

12041208
#if ( OPENSSL_VERSION_NUMBER > 0x009080cfL )
@@ -1564,13 +1568,16 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod)
15641568
// Connect SSL over socket
15651569
cipherStatus = SSL_connect(ssl);
15661570

1567-
sslCipherPointer = SSL_get_current_cipher(ssl);
1568-
cipherbits = SSL_CIPHER_get_bits(sslCipherPointer, NULL);
1569-
15701571
if (cipherStatus == 0)
15711572
{
1572-
SSL_free(ssl);
1573-
return false;
1573+
// An "acceptable" error is eg "client certificate required". We can still produce a list of supported ciphers.
1574+
if (acceptableError())
1575+
cipherStatus = 1;
1576+
else
1577+
{
1578+
SSL_free(ssl);
1579+
return false;
1580+
}
15741581
}
15751582
else if (cipherStatus != 1)
15761583
{
@@ -1590,6 +1597,15 @@ int testCipher(struct sslCheckOptions *options, const SSL_METHOD *sslMethod)
15901597
return false;
15911598
}
15921599

1600+
sslCipherPointer = SSL_get_current_cipher(ssl);
1601+
// If sslCipherPointer is NULL, SSL_CIPHER_get_bits() will segfault
1602+
if (sslCipherPointer == NULL)
1603+
{
1604+
SSL_free(ssl);
1605+
return false;
1606+
}
1607+
cipherbits = SSL_CIPHER_get_bits(sslCipherPointer, NULL);
1608+
15931609
cipherid = SSL_CIPHER_get_id(sslCipherPointer);
15941610
cipherid = cipherid & 0x00ffffff; // remove first byte which is the version (0x03 for TLSv1/SSLv3)
15951611

@@ -1879,7 +1895,7 @@ int checkCertificate(struct sslCheckOptions *options, const SSL_METHOD *sslMetho
18791895

18801896
// Connect SSL over socket
18811897
cipherStatus = SSL_connect(ssl);
1882-
if (cipherStatus == 1)
1898+
if (cipherStatus == 1 || acceptableError())
18831899
{
18841900
// Setup BIO's
18851901
if (!xml_to_stdout) {
@@ -2299,7 +2315,7 @@ int ocspRequest(struct sslCheckOptions *options)
22992315

23002316
// Connect SSL over socket
23012317
cipherStatus = SSL_connect(ssl);
2302-
if (cipherStatus == 1)
2318+
if (cipherStatus == 1 || acceptableError())
23032319
{
23042320
// Setup BIO's
23052321
if (!xml_to_stdout) {
@@ -2568,7 +2584,7 @@ int showCertificate(struct sslCheckOptions *options)
25682584

25692585
// Connect SSL over socket
25702586
cipherStatus = SSL_connect(ssl);
2571-
if (cipherStatus == 1)
2587+
if (cipherStatus == 1 || acceptableError())
25722588
{
25732589
// Setup BIO's
25742590
if (!xml_to_stdout) {
@@ -3011,7 +3027,7 @@ int showTrustedCAs(struct sslCheckOptions *options)
30113027

30123028
// Connect SSL over socket
30133029
cipherStatus = SSL_connect(ssl);
3014-
if (cipherStatus >= 0)
3030+
if (cipherStatus >= 0 || acceptableError())
30153031
{
30163032
// Setup BIO's
30173033
if (!xml_to_stdout) {
@@ -3213,7 +3229,7 @@ int testHost(struct sslCheckOptions *options)
32133229
// Verbose warning about STARTTLS and SSLv3
32143230
if (options->sslVersion == ssl_v3 || options->sslVersion == ssl_all)
32153231
{
3216-
printf_verbose("Some servers will fail to response to SSLv3 ciphers over STARTTLS\nIf your scan hangs, try using the --tlsall option\n\n");
3232+
printf_verbose("Some servers will fail to respond to SSLv3 ciphers over STARTTLS\nIf your scan hangs, try using the --tlsall option\n\n");
32173233
}
32183234

32193235
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,
@@ -3421,6 +3437,9 @@ int testHost(struct sslCheckOptions *options)
34213437
if (status != false)
34223438
status = checkCertificateProtocol(options, SSLv2_client_method());
34233439
#endif
3440+
// Reset status to true, otherwise show trusted CAs below can never run
3441+
// with the default checkCertificate == true
3442+
status = true;
34243443
}
34253444

34263445
// Print client auth trusted CAs
@@ -3466,6 +3485,20 @@ const char *SSL_ERR_to_string (int sslerr)
34663485
}
34673486
}
34683487

3488+
// Define a list of "acceptable" SSL errors which might indicate a client certificate is required, and continue anyway.
3489+
static inline int acceptableError (void)
3490+
{
3491+
// Error 0x14094410 = SSL Alert 40 = Handshake Failure, probably because Server requested client Cert, which we'll treat as a "success".
3492+
// Error 0x14094416 = SSL Alert 46 = Certificate Unknown, treat as "success".
3493+
// Error 0x14094412 = SSL Alert 42 = Bad Certificate - probably means Server requested client Cert. Will also send a list of Acceptable client certificate CA names.
3494+
// SSL Alerts documented here: https://tools.ietf.org/html/rfc5246#section-7.2
3495+
3496+
if (ERR_peek_error() == 0x14094410L || ERR_peek_error() == 0x14094416L || ERR_peek_error() == 0x14094412L)
3497+
return true;
3498+
3499+
return false;
3500+
}
3501+
34693502
int main(int argc, char *argv[])
34703503
{
34713504
// Variables...

sslscan.h

+1
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ static int password_callback(char *, int, int, void *);
198198
int ssl_print_tmp_key(struct sslCheckOptions *, SSL *s);
199199
static int ocsp_resp_cb(SSL *s, void *arg);
200200
int ocsp_certid_print(BIO *bp, OCSP_CERTID *a, int indent);
201+
static inline int acceptableError (void);
201202

202203
int tcpConnect(struct sslCheckOptions *);
203204

0 commit comments

Comments
 (0)