Forbid empty CertificateRequestsupported_signature_algorithms in TLS 1.2.

See the IETF thread here:
https://www.ietf.org/mail-archive/web/tls/current/msg27292.html

In particular, although the original publication of RFC 5246 had a
syntax error in the field (the minimum length was unspecified), there is
an errata from 2012 to fix it to be non-empty.
https://www.rfc-editor.org/errata/eid2864

Currently, when empty, we implicitly interpret it as SHA1/*, matching
the server behavior in missing extension in ClientHellos. However that
text does not support doing it for CertificateRequests, and there is not
much reason to. That default (which is in itself confusing and caused
problems such as older OpenSSL only signing SHA-1 given SNI) was
because, at the time, there were concerns over making any ClientHello
extensions mandatory. This isn't applicable for CertificateRequest,
which can freely advertise their true preferences.

Change-Id: I113494d8f66769fde1362795fb08ff2f471ef31d
Reviewed-on: https://boringssl-review.googlesource.com/c/33524
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
David Benjamin 2018-12-07 12:06:22 -06:00 committed by CQ bot account: commit-bot@chromium.org
parent bf5021a6b8
commit 602f4669ab
3 changed files with 67 additions and 60 deletions

View File

@ -1038,7 +1038,6 @@ static bool ext_sigalgs_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
CBS supported_signature_algorithms; CBS supported_signature_algorithms;
if (!CBS_get_u16_length_prefixed(contents, &supported_signature_algorithms) || if (!CBS_get_u16_length_prefixed(contents, &supported_signature_algorithms) ||
CBS_len(contents) != 0 || CBS_len(contents) != 0 ||
CBS_len(&supported_signature_algorithms) == 0 ||
!tls1_parse_peer_sigalgs(hs, &supported_signature_algorithms)) { !tls1_parse_peer_sigalgs(hs, &supported_signature_algorithms)) {
return false; return false;
} }
@ -3556,7 +3555,10 @@ bool tls1_parse_peer_sigalgs(SSL_HANDSHAKE *hs, const CBS *in_sigalgs) {
return true; return true;
} }
return parse_u16_array(in_sigalgs, &hs->peer_sigalgs); // In all contexts, the signature algorithms list may not be empty. (It may be
// omitted by clients in TLS 1.2, but then the entire extension is omitted.)
return CBS_len(in_sigalgs) != 0 &&
parse_u16_array(in_sigalgs, &hs->peer_sigalgs);
} }
bool tls1_get_legacy_signature_algorithm(uint16_t *out, const EVP_PKEY *pkey) { bool tls1_get_legacy_signature_algorithm(uint16_t *out, const EVP_PKEY *pkey) {

View File

@ -9306,26 +9306,8 @@ func addSignatureAlgorithmTests() {
expectedError: ":WRONG_SIGNATURE_TYPE:", expectedError: ":WRONG_SIGNATURE_TYPE:",
}) })
// Test that, if the list is missing, the peer falls back to SHA-1 in // Test that, if the ClientHello list is missing, the server falls back
// TLS 1.2, but not TLS 1.3. // to SHA-1 in TLS 1.2, but not TLS 1.3.
testCases = append(testCases, testCase{
name: "ClientAuth-SHA1-Fallback-RSA",
config: Config{
MaxVersion: VersionTLS12,
ClientAuth: RequireAnyClientCert,
VerifySignatureAlgorithms: []signatureAlgorithm{
signatureRSAPKCS1WithSHA1,
},
Bugs: ProtocolBugs{
NoSignatureAlgorithms: true,
},
},
flags: []string{
"-cert-file", path.Join(*resourceDir, rsaCertificateFile),
"-key-file", path.Join(*resourceDir, rsaKeyFile),
},
})
testCases = append(testCases, testCase{ testCases = append(testCases, testCase{
testType: serverTest, testType: serverTest,
name: "ServerAuth-SHA1-Fallback-RSA", name: "ServerAuth-SHA1-Fallback-RSA",
@ -9344,24 +9326,6 @@ func addSignatureAlgorithmTests() {
}, },
}) })
testCases = append(testCases, testCase{
name: "ClientAuth-SHA1-Fallback-ECDSA",
config: Config{
MaxVersion: VersionTLS12,
ClientAuth: RequireAnyClientCert,
VerifySignatureAlgorithms: []signatureAlgorithm{
signatureECDSAWithSHA1,
},
Bugs: ProtocolBugs{
NoSignatureAlgorithms: true,
},
},
flags: []string{
"-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile),
"-key-file", path.Join(*resourceDir, ecdsaP256KeyFile),
},
})
testCases = append(testCases, testCase{ testCases = append(testCases, testCase{
testType: serverTest, testType: serverTest,
name: "ServerAuth-SHA1-Fallback-ECDSA", name: "ServerAuth-SHA1-Fallback-ECDSA",
@ -9380,6 +9344,66 @@ func addSignatureAlgorithmTests() {
}, },
}) })
testCases = append(testCases, testCase{
testType: serverTest,
name: "ServerAuth-NoFallback-TLS13",
config: Config{
MaxVersion: VersionTLS13,
VerifySignatureAlgorithms: []signatureAlgorithm{
signatureRSAPKCS1WithSHA1,
},
Bugs: ProtocolBugs{
NoSignatureAlgorithms: true,
},
},
shouldFail: true,
expectedError: ":NO_COMMON_SIGNATURE_ALGORITHMS:",
})
// The CertificateRequest list, however, may never be omitted. It is a
// syntax error for it to be empty.
testCases = append(testCases, testCase{
name: "ClientAuth-NoFallback-RSA",
config: Config{
MaxVersion: VersionTLS12,
ClientAuth: RequireAnyClientCert,
VerifySignatureAlgorithms: []signatureAlgorithm{
signatureRSAPKCS1WithSHA1,
},
Bugs: ProtocolBugs{
NoSignatureAlgorithms: true,
},
},
flags: []string{
"-cert-file", path.Join(*resourceDir, rsaCertificateFile),
"-key-file", path.Join(*resourceDir, rsaKeyFile),
},
shouldFail: true,
expectedError: ":DECODE_ERROR:",
expectedLocalError: "remote error: error decoding message",
})
testCases = append(testCases, testCase{
name: "ClientAuth-NoFallback-ECDSA",
config: Config{
MaxVersion: VersionTLS12,
ClientAuth: RequireAnyClientCert,
VerifySignatureAlgorithms: []signatureAlgorithm{
signatureECDSAWithSHA1,
},
Bugs: ProtocolBugs{
NoSignatureAlgorithms: true,
},
},
flags: []string{
"-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile),
"-key-file", path.Join(*resourceDir, ecdsaP256KeyFile),
},
shouldFail: true,
expectedError: ":DECODE_ERROR:",
expectedLocalError: "remote error: error decoding message",
})
testCases = append(testCases, testCase{ testCases = append(testCases, testCase{
name: "ClientAuth-NoFallback-TLS13", name: "ClientAuth-NoFallback-TLS13",
config: Config{ config: Config{
@ -9396,29 +9420,11 @@ func addSignatureAlgorithmTests() {
"-cert-file", path.Join(*resourceDir, rsaCertificateFile), "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
"-key-file", path.Join(*resourceDir, rsaKeyFile), "-key-file", path.Join(*resourceDir, rsaKeyFile),
}, },
shouldFail: true, shouldFail: true,
// An empty CertificateRequest signature algorithm list is a
// syntax error in TLS 1.3.
expectedError: ":DECODE_ERROR:", expectedError: ":DECODE_ERROR:",
expectedLocalError: "remote error: error decoding message", expectedLocalError: "remote error: error decoding message",
}) })
testCases = append(testCases, testCase{
testType: serverTest,
name: "ServerAuth-NoFallback-TLS13",
config: Config{
MaxVersion: VersionTLS13,
VerifySignatureAlgorithms: []signatureAlgorithm{
signatureRSAPKCS1WithSHA1,
},
Bugs: ProtocolBugs{
NoSignatureAlgorithms: true,
},
},
shouldFail: true,
expectedError: ":NO_COMMON_SIGNATURE_ALGORITHMS:",
})
// Test that signature preferences are enforced. BoringSSL does not // Test that signature preferences are enforced. BoringSSL does not
// implement MD5 signatures. // implement MD5 signatures.
testCases = append(testCases, testCase{ testCases = append(testCases, testCase{

View File

@ -506,7 +506,6 @@ static enum ssl_hs_wait_t do_read_certificate_request(SSL_HANDSHAKE *hs) {
!have_sigalgs || !have_sigalgs ||
!CBS_get_u16_length_prefixed(&sigalgs, !CBS_get_u16_length_prefixed(&sigalgs,
&supported_signature_algorithms) || &supported_signature_algorithms) ||
CBS_len(&supported_signature_algorithms) == 0 ||
!tls1_parse_peer_sigalgs(hs, &supported_signature_algorithms)) { !tls1_parse_peer_sigalgs(hs, &supported_signature_algorithms)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, alert); ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);