The branch master has been updated via 86de658a84a379ad9e7b8b93bb66adb8e218f4c8 (commit) via b4cb7eb7df2982e4f8d5a175e5c43d601ca7e727 (commit) via ad4dd362e036b8481d51e1bfc6e9322b6cf074dc (commit) via 717a265aa5f618fb30f857f240f6b2b0ab7ad4c7 (commit) from 0cb8c9d85e9d5690670d6f1f02e8ccc756520210 (commit)
- Log ----------------------------------------------------------------- commit 86de658a84a379ad9e7b8b93bb66adb8e218f4c8 Author: Dr. Stephen Henson <st...@openssl.org> Date: Wed Feb 15 22:16:09 2017 +0000 Add client auth TLS 1.3 certificate selection tests Reviewed-by: Rich Salz <rs...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/2643) commit b4cb7eb7df2982e4f8d5a175e5c43d601ca7e727 Author: Dr. Stephen Henson <st...@openssl.org> Date: Wed Feb 15 22:03:04 2017 +0000 Add ECDSA client certificates Reviewed-by: Rich Salz <rs...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/2643) commit ad4dd362e036b8481d51e1bfc6e9322b6cf074dc Author: Dr. Stephen Henson <st...@openssl.org> Date: Wed Feb 15 16:23:49 2017 +0000 Use tls_choose_sigalg for client auth. For client auth call tls_choose_sigalg to select the certificate and signature algorithm. Use the selected algorithm in tls_construct_cert_verify. Remove obsolete tls12_get_sigandhash. Reviewed-by: Rich Salz <rs...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/2643) commit 717a265aa5f618fb30f857f240f6b2b0ab7ad4c7 Author: Dr. Stephen Henson <st...@openssl.org> Date: Wed Feb 15 16:19:43 2017 +0000 Add client side support to tls_choose_sigalg. Select appropriate signature algorithm and certificate for client authentication using tls_choose_sigalg. A lot of selection logic is very similar except not finding a certificate is not a fatal error: we just do not present a certificate. For TLS 1.2 and earlier we only check the current certificate is suitable (for compatibility with previous logic) for TLS 1.3 (where there are no compatibility issues) we support multiple client certificates for different algorithms. Reviewed-by: Rich Salz <rs...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/2643) ----------------------------------------------------------------------- Summary of changes: ssl/ssl_locl.h | 2 - ssl/statem/statem_clnt.c | 4 +- ssl/statem/statem_lib.c | 27 +++-- ssl/t1_lib.c | 130 +++++++++------------ .../{ca-cert.pem => ee-ecdsa-client-chain.pem} | 15 +++ test/certs/ee-ecdsa-key.pem | 5 + test/ssl-tests/20-cert-select.conf.in | 51 +++++++- 7 files changed, 139 insertions(+), 95 deletions(-) copy test/certs/{ca-cert.pem => ee-ecdsa-client-chain.pem} (54%) create mode 100644 test/certs/ee-ecdsa-key.pem diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index e1bce30..6f83877 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -2260,8 +2260,6 @@ __owur TICKET_RETURN tls_decrypt_ticket(SSL *s, const unsigned char *etick, __owur int tls_use_ticket(SSL *s); -__owur int tls12_get_sigandhash(SSL *s, WPACKET *pkt, const EVP_PKEY *pk, - const EVP_MD *md, int *ispss); void ssl_set_sig_mask(uint32_t *pmask_a, SSL *s, int op); __owur int tls1_set_sigalgs_list(CERT *c, const char *str, int client); diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c index 8ca3c4c..4923e24 100644 --- a/ssl/statem/statem_clnt.c +++ b/ssl/statem/statem_clnt.c @@ -3090,10 +3090,8 @@ int tls_client_key_exchange_post_work(SSL *s) */ static int ssl3_check_client_certificate(SSL *s) { - if (!s->cert || !s->cert->key->x509 || !s->cert->key->privatekey) - return 0; /* If no suitable signature algorithm can't use certificate */ - if (SSL_USE_SIGALGS(s) && !s->s3->tmp.md[s->cert->key - s->cert->pkeys]) + if (!tls_choose_sigalg(s, NULL) || s->s3->tmp.sigalg == NULL) return 0; /* * If strict mode check suitability of chain before using it. This also diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c index 31156fd..ed07266 100644 --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c @@ -171,17 +171,27 @@ static int get_cert_verify_tbs_data(SSL *s, unsigned char *tls13tbs, int tls_construct_cert_verify(SSL *s, WPACKET *pkt) { - EVP_PKEY *pkey = s->cert->key->privatekey; - const EVP_MD *md = s->s3->tmp.md[s->cert->key - s->cert->pkeys]; + EVP_PKEY *pkey = NULL; + const EVP_MD *md = NULL; EVP_MD_CTX *mctx = NULL; EVP_PKEY_CTX *pctx = NULL; size_t hdatalen = 0, siglen = 0; void *hdata; unsigned char *sig = NULL; unsigned char tls13tbs[TLS13_TBS_PREAMBLE_SIZE + EVP_MAX_MD_SIZE]; - int pktype, ispss = 0; + const SIGALG_LOOKUP *lu = s->s3->tmp.sigalg; - pktype = EVP_PKEY_id(pkey); + if (lu == NULL || s->s3->tmp.cert == NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_CERT_VERIFY, ERR_R_INTERNAL_ERROR); + goto err; + } + pkey = s->s3->tmp.cert->privatekey; + md = ssl_md(lu->hash_idx); + + if (pkey == NULL || md == NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_CERT_VERIFY, ERR_R_INTERNAL_ERROR); + goto err; + } mctx = EVP_MD_CTX_new(); if (mctx == NULL) { @@ -195,13 +205,10 @@ int tls_construct_cert_verify(SSL *s, WPACKET *pkt) goto err; } - if (SSL_USE_SIGALGS(s) && !tls12_get_sigandhash(s, pkt, pkey, md, &ispss)) { + if (SSL_USE_SIGALGS(s) && !WPACKET_put_bytes_u16(pkt, lu->sigalg)) { SSLerr(SSL_F_TLS_CONSTRUCT_CERT_VERIFY, ERR_R_INTERNAL_ERROR); goto err; } -#ifdef SSL_DEBUG - fprintf(stderr, "Using client alg %s\n", EVP_MD_name(md)); -#endif siglen = EVP_PKEY_size(pkey); sig = OPENSSL_malloc(siglen); if (sig == NULL) { @@ -215,7 +222,7 @@ int tls_construct_cert_verify(SSL *s, WPACKET *pkt) goto err; } - if (ispss) { + if (lu->sig == EVP_PKEY_RSA_PSS) { if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) <= 0 || EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, RSA_PSS_SALTLEN_DIGEST) <= 0) { @@ -238,6 +245,8 @@ int tls_construct_cert_verify(SSL *s, WPACKET *pkt) #ifndef OPENSSL_NO_GOST { + int pktype = lu->sig; + if (pktype == NID_id_GostR3410_2001 || pktype == NID_id_GostR3410_2012_256 || pktype == NID_id_GostR3410_2012_512) diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 787f487..fc9ae68 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -1349,58 +1349,6 @@ TICKET_RETURN tls_decrypt_ticket(SSL *s, const unsigned char *etick, return ret; } -int tls12_get_sigandhash(SSL *s, WPACKET *pkt, const EVP_PKEY *pk, - const EVP_MD *md, int *ispss) -{ - int md_id, sig_id; - size_t i; - const SIGALG_LOOKUP *curr; - - if (md == NULL) - return 0; - md_id = EVP_MD_type(md); - sig_id = EVP_PKEY_id(pk); - if (md_id == NID_undef) - return 0; - /* For TLS 1.3 only allow RSA-PSS */ - if (SSL_IS_TLS13(s) && sig_id == EVP_PKEY_RSA) - sig_id = EVP_PKEY_RSA_PSS; - - if (s->s3->tmp.peer_sigalgs == NULL) { - /* Should never happen: we abort if no sigalgs extension and TLS 1.3 */ - if (SSL_IS_TLS13(s)) - return 0; - /* For TLS 1.2 and no sigalgs lookup using complete table */ - for (i = 0, curr = sigalg_lookup_tbl; i < OSSL_NELEM(sigalg_lookup_tbl); - i++, curr++) { - if (curr->hash == md_id && curr->sig == sig_id) { - if (!WPACKET_put_bytes_u16(pkt, curr->sigalg)) - return 0; - *ispss = curr->sig == EVP_PKEY_RSA_PSS; - return 1; - } - } - return 0; - } - - for (i = 0; i < s->cert->shared_sigalgslen; i++) { - curr = s->cert->shared_sigalgs[i]; - - /* - * Look for matching key and hash. If key type is RSA also match PSS - * signature type. - */ - if (curr->hash == md_id && (curr->sig == sig_id - || (sig_id == EVP_PKEY_RSA && curr->sig == EVP_PKEY_RSA_PSS))){ - if (!WPACKET_put_bytes_u16(pkt, curr->sigalg)) - return 0; - *ispss = curr->sig == EVP_PKEY_RSA_PSS; - return 1; - } - } - return 0; -} - static int tls12_get_pkey_idx(int sig_nid) { switch (sig_nid) { @@ -2316,13 +2264,23 @@ int ssl_security_cert_chain(SSL *s, STACK_OF(X509) *sk, X509 *x, int vfy) /* * Choose an appropriate signature algorithm based on available certificates - * Set current certificate and digest to match chosen algorithm. + * Sets chosen certificate and signature algorithm. + * + * For servers if we fail to find a required certificate it is a fatal error + * and an appropriate error code is set and the TLS alert set in *al. + * + * For clients al is set to NULL. If a certificate is not suitable it is not + * a fatal error: we will either try another certificate or not present one + * to the server. In this case no error is set. */ int tls_choose_sigalg(SSL *s, int *al) { int idx = -1; const SIGALG_LOOKUP *lu = NULL; + s->s3->tmp.cert = NULL; + s->s3->tmp.sigalg = NULL; + if (SSL_IS_TLS13(s)) { size_t i; #ifndef OPENSSL_NO_EC @@ -2357,37 +2315,47 @@ int tls_choose_sigalg(SSL *s, int *al) break; } if (i == s->cert->shared_sigalgslen) { + if (al == NULL) + return 1; *al = SSL_AD_HANDSHAKE_FAILURE; SSLerr(SSL_F_TLS_CHOOSE_SIGALG, SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM); return 0; } } else { - /* Find index corresponding to ciphersuite */ - idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher); - /* If no certificate for ciphersuite return */ - if (idx == -1) { - s->s3->tmp.cert = NULL; - s->s3->tmp.sigalg = NULL; - return 1; - } - if (idx == SSL_PKEY_GOST_EC) { - /* Work out which GOST certificate is avaiable */ - if (ssl_has_cert(s, SSL_PKEY_GOST12_512)) { - idx = SSL_PKEY_GOST12_512; - } else if (ssl_has_cert(s, SSL_PKEY_GOST12_256)) { - idx = SSL_PKEY_GOST12_256; - } else if (ssl_has_cert(s, SSL_PKEY_GOST01)) { - idx = SSL_PKEY_GOST01; - } else { + if (s->server) { + /* Find index corresponding to ciphersuite */ + idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher); + /* If no certificate for ciphersuite return */ + if (idx == -1) + return 1; + if (idx == SSL_PKEY_GOST_EC) { + /* Work out which GOST certificate is avaiable */ + if (ssl_has_cert(s, SSL_PKEY_GOST12_512)) { + idx = SSL_PKEY_GOST12_512; + } else if (ssl_has_cert(s, SSL_PKEY_GOST12_256)) { + idx = SSL_PKEY_GOST12_256; + } else if (ssl_has_cert(s, SSL_PKEY_GOST01)) { + idx = SSL_PKEY_GOST01; + } else { + if (al == NULL) + return 1; + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_CHOOSE_SIGALG, ERR_R_INTERNAL_ERROR); + return 0; + } + } else if (!ssl_has_cert(s, idx)) { + if (al == NULL) + return 1; *al = SSL_AD_INTERNAL_ERROR; SSLerr(SSL_F_TLS_CHOOSE_SIGALG, ERR_R_INTERNAL_ERROR); return 0; } - } else if (!ssl_has_cert(s, idx)) { - *al = SSL_AD_INTERNAL_ERROR; - SSLerr(SSL_F_TLS_CHOOSE_SIGALG, ERR_R_INTERNAL_ERROR); - return 0; + } else { + /* Find index for client certificate */ + idx = s->cert->key - s->cert->pkeys; + if (!ssl_has_cert(s, idx)) + return 1; } if (SSL_USE_SIGALGS(s)) { @@ -2406,6 +2374,8 @@ int tls_choose_sigalg(SSL *s, int *al) break; } if (i == s->cert->shared_sigalgslen) { + if (al == NULL) + return 1; *al = SSL_AD_INTERNAL_ERROR; SSLerr(SSL_F_TLS_CHOOSE_SIGALG, ERR_R_INTERNAL_ERROR); return 0; @@ -2418,6 +2388,8 @@ int tls_choose_sigalg(SSL *s, int *al) size_t sent_sigslen, i; if ((lu = tls1_get_legacy_sigalg(s, idx)) == NULL) { + if (al == NULL) + return 1; *al = SSL_AD_INTERNAL_ERROR; SSLerr(SSL_F_TLS_CHOOSE_SIGALG, ERR_R_INTERNAL_ERROR); return 0; @@ -2430,6 +2402,8 @@ int tls_choose_sigalg(SSL *s, int *al) break; } if (i == sent_sigslen) { + if (al == NULL) + return 1; SSLerr(SSL_F_TLS_CHOOSE_SIGALG, SSL_R_WRONG_SIGNATURE_TYPE); *al = SSL_AD_HANDSHAKE_FAILURE; return 0; @@ -2437,6 +2411,8 @@ int tls_choose_sigalg(SSL *s, int *al) } } else { if ((lu = tls1_get_legacy_sigalg(s, idx)) == NULL) { + if (al == NULL) + return 1; *al = SSL_AD_INTERNAL_ERROR; SSLerr(SSL_F_TLS_CHOOSE_SIGALG, ERR_R_INTERNAL_ERROR); return 0; @@ -2444,8 +2420,10 @@ int tls_choose_sigalg(SSL *s, int *al) } } if (idx == -1) { - *al = SSL_AD_INTERNAL_ERROR; - SSLerr(SSL_F_TLS_CHOOSE_SIGALG, ERR_R_INTERNAL_ERROR); + if (al != NULL) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_CHOOSE_SIGALG, ERR_R_INTERNAL_ERROR); + } return 0; } s->s3->tmp.cert = &s->cert->pkeys[idx]; diff --git a/test/certs/ca-cert.pem b/test/certs/ee-ecdsa-client-chain.pem similarity index 54% copy from test/certs/ca-cert.pem copy to test/certs/ee-ecdsa-client-chain.pem index f6bc233..ba04fdb 100644 --- a/test/certs/ca-cert.pem +++ b/test/certs/ee-ecdsa-client-chain.pem @@ -1,4 +1,19 @@ -----BEGIN CERTIFICATE----- +MIICXDCCAUSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDDAJDQTAg +Fw0xNzAyMTUxOTMxMTBaGA8yMTE3MDIxNjE5MzExMFowHDEaMBgGA1UEAwwRRUNE +U0EgQ2xpZW50IEF1dGgwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATpeZcBUFBT +zmRIEaNlNcLA3+dvPgc5T3y2/Cut6ixNHjGCM1KzMSyZC2LwBhtKAl1CJxAfPvoP +WECveS18FWXWo4GAMH4wHQYDVR0OBBYEFKP225wj9a3okk5Y2GvNHvJqH8sAMB8G +A1UdIwQYMBaAFLQRM/HX4l73U54gIhBPhga/H8leMAkGA1UdEwQCMAAwEwYDVR0l +BAwwCgYIKwYBBQUHAwIwHAYDVR0RBBUwE4IRRUNEU0EgQ2xpZW50IEF1dGgwDQYJ +KoZIhvcNAQELBQADggEBAG8P/XEQnwHrd3O6GIAE5/Yloxqrjw5CoxbKmmVwrojz +JGMHXPqE+V+RGUUnvP9Za8mIxtTi6hfvPRGNxRUhsPHXcQ52kwYf6r/ZeSXT0yFF +ITVFFXM63p/jfF1NQgeEQ2NgPYJ9H6WTQbOu7EkaF/2E//DPUf93is8DKUgFLtdM +p5Afb4yMul64wS2nHZIa3oR+15BDCQJ0FQtYX5bM2+6AZ0EZZT6q6t1cRRW8Tk4d +YyUS5SSfxEdhdxnLPM5n88IYFhHV5klhgfp42CRXOWgLSBQeBZ8LqgUs7buHSxv5 +duOKJn5+mGvktlxvThrXpKgBx3yApThRKmBvb6Avrq8= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- MIIC7DCCAdSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdSb290 IENBMCAXDTE2MDExNTA4MTk0OVoYDzIxMTYwMTE2MDgxOTQ5WjANMQswCQYDVQQD DAJDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJadpD0ASxxfxsvd diff --git a/test/certs/ee-ecdsa-key.pem b/test/certs/ee-ecdsa-key.pem new file mode 100644 index 0000000..6844a0b --- /dev/null +++ b/test/certs/ee-ecdsa-key.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgi5sKk1Y8QjhMSK6P +69wCABpFCv9/aCaMpLhlzAMfEjOhRANCAATpeZcBUFBTzmRIEaNlNcLA3+dvPgc5 +T3y2/Cut6ixNHjGCM1KzMSyZC2LwBhtKAl1CJxAfPvoPWECveS18FWXW +-----END PRIVATE KEY----- diff --git a/test/ssl-tests/20-cert-select.conf.in b/test/ssl-tests/20-cert-select.conf.in index 2036d2c..3d36a0e 100644 --- a/test/ssl-tests/20-cert-select.conf.in +++ b/test/ssl-tests/20-cert-select.conf.in @@ -11,9 +11,11 @@ use OpenSSL::Test::Utils; my $dir_sep = $^O ne "VMS" ? "/" : ""; +my $cert_dir = "\${ENV::TEST_CERTS_DIR}${dir_sep}"; + my $server = { - "ECDSA.Certificate" => "\${ENV::TEST_CERTS_DIR}${dir_sep}server-ecdsa-cert.pem", - "ECDSA.PrivateKey" => "\${ENV::TEST_CERTS_DIR}${dir_sep}server-ecdsa-key.pem", + "ECDSA.Certificate" => "${cert_dir}server-ecdsa-cert.pem", + "ECDSA.PrivateKey" => "${cert_dir}server-ecdsa-key.pem", "MaxProtocol" => "TLSv1.2" }; @@ -122,8 +124,17 @@ our @tests = ( my $server_tls_1_3 = { - "ECDSA.Certificate" => "\${ENV::TEST_CERTS_DIR}${dir_sep}server-ecdsa-cert.pem", - "ECDSA.PrivateKey" => "\${ENV::TEST_CERTS_DIR}${dir_sep}server-ecdsa-key.pem", + "ECDSA.Certificate" => "${cert_dir}server-ecdsa-cert.pem", + "ECDSA.PrivateKey" => "${cert_dir}server-ecdsa-key.pem", + "MinProtocol" => "TLSv1.3", + "MaxProtocol" => "TLSv1.3" +}; + +my $client_tls_1_3 = { + "RSA.Certificate" => "${cert_dir}ee-client-chain.pem", + "RSA.PrivateKey" => "${cert_dir}ee-key.pem", + "ECDSA.Certificate" => "${cert_dir}ee-ecdsa-client-chain.pem", + "ECDSA.PrivateKey" => "${cert_dir}ee-ecdsa-key.pem", "MinProtocol" => "TLSv1.3", "MaxProtocol" => "TLSv1.3" }; @@ -203,7 +214,37 @@ my @tests_tls_1_3 = ( "ExpectedServerSignType" => "RSA-PSS", "ExpectedResult" => "Success" }, - } + }, + { + name => "TLS 1.3 RSA Client Auth Signature Algorithm Selection", + server => { + "ClientSignatureAlgorithms" => "PSS+SHA256", + "VerifyCAFile" => "${cert_dir}root-cert.pem", + "VerifyMode" => "Require" + }, + client => $client_tls_1_3, + test => { + "ExpectedClientCertType" => "RSA", + "ExpectedClientSignHash" => "SHA256", + "ExpectedClientSignType" => "RSA-PSS", + "ExpectedResult" => "Success" + }, + }, + { + name => "TLS 1.3 ECDSA Client Auth Signature Algorithm Selection", + server => { + "ClientSignatureAlgorithms" => "ECDSA+SHA256", + "VerifyCAFile" => "${cert_dir}root-cert.pem", + "VerifyMode" => "Require" + }, + client => $client_tls_1_3, + test => { + "ExpectedClientCertType" => "P-256", + "ExpectedClientSignHash" => "SHA256", + "ExpectedClientSignType" => "EC", + "ExpectedResult" => "Success" + }, + }, ); push @tests, @tests_tls_1_3 unless disabled("tls1_3"); _____ openssl-commits mailing list To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-commits