[openssl-commits] [openssl] master update

Dr. Stephen Henson steve at openssl.org
Wed Feb 15 02:24:36 UTC 2017


The branch master has been updated
       via  a34a9df0712ac27256ec48e6f88c61064613ac08 (commit)
       via  a497cf25162e100ad46bd08222b6e7584b2d5bee (commit)
       via  f695571e10a3e63930424940acc8dafd13c6c35c (commit)
       via  f365a3e2e552e36f5c885953f5a361267f0d06c6 (commit)
       via  0972bc5cedfb3c8dcf7eae3ab010ed3b47a6f186 (commit)
       via  4a419f60188405d6ecc450526b6aa926638d1db2 (commit)
       via  4020c0b33b25f829ca68976970d44227d115eb9e (commit)
      from  7e12cdb52e3f4beff050caeecf3634870bb9a7c4 (commit)


- Log -----------------------------------------------------------------
commit a34a9df0712ac27256ec48e6f88c61064613ac08
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Tue Feb 14 14:27:15 2017 +0000

    Skip curve check if sigalg doesn't specify a curve.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2623)

commit a497cf25162e100ad46bd08222b6e7584b2d5bee
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Tue Feb 14 00:35:26 2017 +0000

    Use CERT_PKEY pointer instead of index
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2623)

commit f695571e10a3e63930424940acc8dafd13c6c35c
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Mon Feb 13 18:07:00 2017 +0000

    Simplify tls_construct_server_key_exchange
    
    Use negotiated signature algorithm and certificate index in
    tls_construct_key_exchange instead of recalculating it.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2623)

commit f365a3e2e552e36f5c885953f5a361267f0d06c6
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Mon Feb 13 16:32:06 2017 +0000

    Use cert_index and sigalg
    
    Now the certificate and signature algorithm is set in one place we
    can use it directly insetad of recalculating it. The old functions
    ssl_get_server_send_pkey() and ssl_get_server_cert_index() are no
    longer required.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2623)

commit 0972bc5cedfb3c8dcf7eae3ab010ed3b47a6f186
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Mon Feb 13 16:04:07 2017 +0000

    Add sigalg for earlier TLS versions
    
    Update tls_choose_sigalg to choose a signature algorithm for all
    versions of TLS not just 1.3.
    
    For TLS 1.2 we choose the highest preference signature algorithm
    for the chosen ciphersuite.
    
    For TLS 1.1 and earlier the signature algorithm is determined by
    the ciphersuite alone. For RSA we use a special MD5+SHA1 signature
    algorithm.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2623)

commit 4a419f60188405d6ecc450526b6aa926638d1db2
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Mon Feb 13 15:50:43 2017 +0000

    Change tls_choose_sigalg so it can set errors and alerts.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2623)

commit 4020c0b33b25f829ca68976970d44227d115eb9e
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Mon Feb 13 15:40:21 2017 +0000

    add ssl_has_cert
    
    Add inline function ssl_has_cert which checks to see if a certificate and
    private key for a given index are not NULL.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2623)

-----------------------------------------------------------------------

Summary of changes:
 include/openssl/ssl.h    |   1 +
 ssl/s3_lib.c             |   8 +--
 ssl/ssl_err.c            |   1 +
 ssl/ssl_lib.c            | 105 +++-------------------------
 ssl/ssl_locl.h           |  25 ++++---
 ssl/statem/statem_clnt.c |  10 +--
 ssl/statem/statem_lib.c  |  11 +--
 ssl/statem/statem_srvr.c | 143 +++++++++++++++++----------------------
 ssl/t1_lib.c             | 173 ++++++++++++++++++++++++++++++++++++++++-------
 9 files changed, 250 insertions(+), 227 deletions(-)

diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 96a5558..f2b6198 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -2259,6 +2259,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_TLS1_PRF                                   284
 # define SSL_F_TLS1_SETUP_KEY_BLOCK                       211
 # define SSL_F_TLS1_SET_SERVER_SIGALGS                    335
+# define SSL_F_TLS_CHOOSE_SIGALG                          510
 # define SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK          354
 # define SSL_F_TLS_COLLECT_EXTENSIONS                     435
 # define SSL_F_TLS_CONSTRUCT_CERTIFICATE_REQUEST          372
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 8065e15..8537e80 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -3137,12 +3137,11 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
 
     case SSL_CTRL_SET_CURRENT_CERT:
         if (larg == SSL_CERT_SET_SERVER) {
-            CERT_PKEY *cpk;
             const SSL_CIPHER *cipher;
             if (!s->server)
                 return 0;
             cipher = s->s3->tmp.new_cipher;
-            if (!cipher)
+            if (cipher == NULL)
                 return 0;
             /*
              * No certificate for unauthenticated ciphersuites or using SRP
@@ -3150,10 +3149,9 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
              */
             if (cipher->algorithm_auth & (SSL_aNULL | SSL_aSRP))
                 return 2;
-            cpk = ssl_get_server_send_pkey(s);
-            if (!cpk)
+            if (s->s3->tmp.cert == NULL)
                 return 0;
-            s->cert->key = cpk;
+            s->cert->key = s->s3->tmp.cert;
             return 1;
         }
         return ssl_cert_set_current(s->cert, larg);
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index ea5a763..cea6040 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -261,6 +261,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_FUNC(SSL_F_TLS1_PRF), "tls1_PRF"},
     {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "tls1_setup_key_block"},
     {ERR_FUNC(SSL_F_TLS1_SET_SERVER_SIGALGS), "tls1_set_server_sigalgs"},
+    {ERR_FUNC(SSL_F_TLS_CHOOSE_SIGALG), "tls_choose_sigalg"},
     {ERR_FUNC(SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK),
      "tls_client_key_exchange_post_work"},
     {ERR_FUNC(SSL_F_TLS_COLLECT_EXTENSIONS), "tls_collect_extensions"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 11c0a80..1642215 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -2720,16 +2720,12 @@ void SSL_set_cert_cb(SSL *s, int (*cb) (SSL *ssl, void *arg), void *arg)
 
 void ssl_set_masks(SSL *s)
 {
-#if !defined(OPENSSL_NO_EC) || !defined(OPENSSL_NO_GOST)
-    CERT_PKEY *cpk;
-#endif
     CERT *c = s->cert;
     uint32_t *pvalid = s->s3->tmp.valid_flags;
     int rsa_enc, rsa_sign, dh_tmp, dsa_sign;
     unsigned long mask_k, mask_a;
 #ifndef OPENSSL_NO_EC
     int have_ecc_cert, ecdsa_ok;
-    X509 *x = NULL;
 #endif
     if (c == NULL)
         return;
@@ -2755,18 +2751,15 @@ void ssl_set_masks(SSL *s)
 #endif
 
 #ifndef OPENSSL_NO_GOST
-    cpk = &(c->pkeys[SSL_PKEY_GOST12_512]);
-    if (cpk->x509 != NULL && cpk->privatekey != NULL) {
+    if (ssl_has_cert(s, SSL_PKEY_GOST12_512)) {
         mask_k |= SSL_kGOST;
         mask_a |= SSL_aGOST12;
     }
-    cpk = &(c->pkeys[SSL_PKEY_GOST12_256]);
-    if (cpk->x509 != NULL && cpk->privatekey != NULL) {
+    if (ssl_has_cert(s, SSL_PKEY_GOST12_256)) {
         mask_k |= SSL_kGOST;
         mask_a |= SSL_aGOST12;
     }
-    cpk = &(c->pkeys[SSL_PKEY_GOST01]);
-    if (cpk->x509 != NULL && cpk->privatekey != NULL) {
+    if (ssl_has_cert(s, SSL_PKEY_GOST01)) {
         mask_k |= SSL_kGOST;
         mask_a |= SSL_aGOST01;
     }
@@ -2795,9 +2788,7 @@ void ssl_set_masks(SSL *s)
 #ifndef OPENSSL_NO_EC
     if (have_ecc_cert) {
         uint32_t ex_kusage;
-        cpk = &c->pkeys[SSL_PKEY_ECC];
-        x = cpk->x509;
-        ex_kusage = X509_get_key_usage(x);
+        ex_kusage = X509_get_key_usage(c->pkeys[SSL_PKEY_ECC].x509);
         ecdsa_ok = ex_kusage & X509v3_KU_DIGITAL_SIGNATURE;
         if (!(pvalid[SSL_PKEY_ECC] & CERT_PKEY_SIGN))
             ecdsa_ok = 0;
@@ -2842,97 +2833,17 @@ int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s)
 
 #endif
 
-static int ssl_get_server_cert_index(const SSL *s)
-{
-    int idx;
-
-    if (SSL_IS_TLS13(s)) {
-        if (s->s3->tmp.sigalg == NULL) {
-            SSLerr(SSL_F_SSL_GET_SERVER_CERT_INDEX, ERR_R_INTERNAL_ERROR);
-            return -1;
-        }
-        return s->s3->tmp.cert_idx;
-    }
-
-    idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher);
-    if (idx == SSL_PKEY_GOST_EC) {
-        if (s->cert->pkeys[SSL_PKEY_GOST12_512].x509)
-            idx = SSL_PKEY_GOST12_512;
-        else if (s->cert->pkeys[SSL_PKEY_GOST12_256].x509)
-            idx = SSL_PKEY_GOST12_256;
-        else if (s->cert->pkeys[SSL_PKEY_GOST01].x509)
-            idx = SSL_PKEY_GOST01;
-        else
-            idx = -1;
-    }
-    if (idx == -1)
-        SSLerr(SSL_F_SSL_GET_SERVER_CERT_INDEX, ERR_R_INTERNAL_ERROR);
-    return idx;
-}
-
-CERT_PKEY *ssl_get_server_send_pkey(SSL *s)
-{
-    CERT *c;
-    int i;
-
-    c = s->cert;
-    if (!s->s3 || !s->s3->tmp.new_cipher)
-        return NULL;
-    ssl_set_masks(s);
-
-    i = ssl_get_server_cert_index(s);
-
-    /* This may or may not be an error. */
-    if (i < 0)
-        return NULL;
-
-    /* May be NULL. */
-    return &c->pkeys[i];
-}
-
-EVP_PKEY *ssl_get_sign_pkey(SSL *s, const SSL_CIPHER *cipher,
-                            const EVP_MD **pmd)
-{
-    unsigned long alg_a;
-    CERT *c;
-    int idx = -1;
-
-    alg_a = cipher->algorithm_auth;
-    c = s->cert;
-
-    if (alg_a & SSL_aDSS && c->pkeys[SSL_PKEY_DSA_SIGN].privatekey != NULL)
-        idx = SSL_PKEY_DSA_SIGN;
-    else if (alg_a & SSL_aRSA && c->pkeys[SSL_PKEY_RSA].privatekey != NULL)
-            idx = SSL_PKEY_RSA;
-    else if (alg_a & SSL_aECDSA &&
-             c->pkeys[SSL_PKEY_ECC].privatekey != NULL)
-        idx = SSL_PKEY_ECC;
-    if (idx == -1) {
-        SSLerr(SSL_F_SSL_GET_SIGN_PKEY, ERR_R_INTERNAL_ERROR);
-        return (NULL);
-    }
-    if (pmd)
-        *pmd = s->s3->tmp.md[idx];
-    return c->pkeys[idx].privatekey;
-}
-
 int ssl_get_server_cert_serverinfo(SSL *s, const unsigned char **serverinfo,
                                    size_t *serverinfo_length)
 {
-    CERT *c = NULL;
-    int i = 0;
+    CERT_PKEY *cpk = s->s3->tmp.cert;
     *serverinfo_length = 0;
 
-    c = s->cert;
-    i = ssl_get_server_cert_index(s);
-
-    if (i == -1)
-        return 0;
-    if (c->pkeys[i].serverinfo == NULL)
+    if (cpk == NULL || cpk->serverinfo == NULL)
         return 0;
 
-    *serverinfo = c->pkeys[i].serverinfo;
-    *serverinfo_length = c->pkeys[i].serverinfo_length;
+    *serverinfo = cpk->serverinfo;
+    *serverinfo_length = cpk->serverinfo_length;
     return 1;
 }
 
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index df6be64..106ff69 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1213,6 +1213,8 @@ typedef struct sigalg_lookup_st {
     int curve;
 } SIGALG_LOOKUP;
 
+typedef struct cert_pkey_st CERT_PKEY;
+
 typedef struct ssl3_state_st {
     long flags;
     size_t read_mac_secret_size;
@@ -1296,8 +1298,8 @@ typedef struct ssl3_state_st {
 # endif
         /* Signature algorithm we actually use */
         const SIGALG_LOOKUP *sigalg;
-        /* Index of certificate we use */
-        int cert_idx;
+        /* Pointer to certificate we use */
+        CERT_PKEY *cert;
         /*
          * signature algorithms peer reports: e.g. supported signature
          * algorithms extension for server or as part of a certificate
@@ -1491,7 +1493,7 @@ typedef struct dtls1_state_st {
 #  define NAMED_CURVE_TYPE           3
 # endif                         /* OPENSSL_NO_EC */
 
-typedef struct cert_pkey_st {
+struct cert_pkey_st {
     X509 *x509;
     EVP_PKEY *privatekey;
     /* Chain for this certificate */
@@ -1505,7 +1507,7 @@ typedef struct cert_pkey_st {
      */
     unsigned char *serverinfo;
     size_t serverinfo_length;
-} CERT_PKEY;
+};
 /* Retrieve Suite B flags */
 # define tls1_suiteb(s)  (s->cert->cert_flags & SSL_CERT_FLAG_SUITEB_128_LOS)
 /* Uses to check strict mode: suite B modes are always strict */
@@ -1950,6 +1952,15 @@ struct openssl_ssl_test_functions {
 
 const char *ssl_protocol_to_string(int version);
 
+/* Returns true if certificate and private key for 'idx' are present */
+static ossl_inline int ssl_has_cert(const SSL *s, int idx)
+{
+    if (idx < 0 || idx >= SSL_PKEY_NUM)
+        return 0;
+    return s->cert->pkeys[idx].x509 != NULL
+        && s->cert->pkeys[idx].privatekey != NULL;
+}
+
 # ifndef OPENSSL_UNIT_TEST
 
 void ssl_clear_cipher_ctx(SSL *s);
@@ -2003,12 +2014,9 @@ __owur int ssl_ctx_security(const SSL_CTX *ctx, int op, int bits, int nid,
 int ssl_undefined_function(SSL *s);
 __owur int ssl_undefined_void_function(void);
 __owur int ssl_undefined_const_function(const SSL *s);
-__owur CERT_PKEY *ssl_get_server_send_pkey(SSL *s);
 __owur int ssl_get_server_cert_serverinfo(SSL *s,
                                           const unsigned char **serverinfo,
                                           size_t *serverinfo_length);
-__owur EVP_PKEY *ssl_get_sign_pkey(SSL *s, const SSL_CIPHER *c,
-                                   const EVP_MD **pmd);
 __owur int ssl_cert_type(const X509 *x, const EVP_PKEY *pkey);
 void ssl_set_masks(SSL *s);
 __owur STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *s);
@@ -2271,7 +2279,7 @@ __owur int ssl_security_cert(SSL *s, SSL_CTX *ctx, X509 *x, int vfy, int is_ee);
 __owur int ssl_security_cert_chain(SSL *s, STACK_OF(X509) *sk, X509 *ex,
                                    int vfy);
 
-int tls_choose_sigalg(SSL *s);
+int tls_choose_sigalg(SSL *s, int *al);
 
 __owur EVP_MD_CTX *ssl_replace_hash(EVP_MD_CTX **hash, const EVP_MD *md);
 void ssl_clear_hash_ctx(EVP_MD_CTX **hash);
@@ -2280,6 +2288,7 @@ __owur int tls12_copy_sigalgs(SSL *s, WPACKET *pkt,
                               const uint16_t *psig, size_t psiglen);
 __owur int tls1_save_sigalgs(SSL *s, PACKET *pkt);
 __owur int tls1_process_sigalgs(SSL *s);
+__owur int tls1_set_peer_legacy_sigalg(SSL *s, const EVP_PKEY *pkey);
 __owur size_t tls12_get_psigalgs(SSL *s, int sent, const uint16_t **psigs);
 __owur int tls12_check_peer_sigalg(SSL *s, uint16_t, EVP_PKEY *pkey);
 void ssl_set_client_disabled(SSL *s);
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index 152600b..8ca3c4c 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -2058,16 +2058,16 @@ MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
                 al = SSL_AD_DECODE_ERROR;
                 goto err;
             }
-            md = ssl_md(s->s3->tmp.peer_sigalg->hash_idx);
 #ifdef SSL_DEBUG
             fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
 #endif
-        } else if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA) {
-            md = EVP_md5_sha1();
-        } else {
-            md = EVP_sha1();
+        } else if (!tls1_set_peer_legacy_sigalg(s, pkey)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            goto err;
         }
 
+        md = ssl_md(s->s3->tmp.peer_sigalg->hash_idx);
+
         if (!PACKET_get_length_prefixed_2(pkt, &signature)
             || PACKET_remaining(pkt) != 0) {
             al = SSL_AD_DECODE_ERROR;
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index 3a03ada..31156fd 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -331,21 +331,16 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt)
                 al = SSL_AD_DECODE_ERROR;
                 goto f_err;
             }
-            md = ssl_md(s->s3->tmp.peer_sigalg->hash_idx);
 #ifdef SSL_DEBUG
             fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
 #endif
-        } else {
-            /* Use default digest for this key type */
-            int idx = ssl_cert_type(NULL, pkey);
-            if (idx >= 0)
-                md = s->s3->tmp.md[idx];
-            if (md == NULL) {
+        } else if (!tls1_set_peer_legacy_sigalg(s, pkey)) {
                 al = SSL_AD_INTERNAL_ERROR;
                 goto f_err;
-            }
         }
 
+        md = ssl_md(s->s3->tmp.peer_sigalg->hash_idx);
+
         if (!PACKET_get_net_2(pkt, &len)) {
             SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_LENGTH_MISMATCH);
             al = SSL_AD_DECODE_ERROR;
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 93ba63e..2330bde 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -1759,15 +1759,14 @@ static int tls_handle_status_request(SSL *s, int *al)
     if (s->ext.status_type != TLSEXT_STATUSTYPE_nothing && s->ctx != NULL
             && s->ctx->ext.status_cb != NULL) {
         int ret;
-        CERT_PKEY *certpkey = ssl_get_server_send_pkey(s);
 
         /* If no certificate can't return certificate status */
-        if (certpkey != NULL) {
+        if (s->s3->tmp.cert != NULL) {
             /*
              * Set current certificate to one we will use so SSL_get_certificate
              * et al can pick it up.
              */
-            s->cert->key = certpkey;
+            s->cert->key = s->s3->tmp.cert;
             ret = s->ctx->ext.status_cb(s, s->ctx->ext.status_arg);
             switch (ret) {
                 /* We don't want to send a status request response */
@@ -1822,12 +1821,8 @@ WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst)
                 goto f_err;
             }
             s->s3->tmp.new_cipher = cipher;
-            if (!tls_choose_sigalg(s)) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO,
-                       SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM);
+            if (!tls_choose_sigalg(s, &al))
                 goto f_err;
-            }
             /* check whether we should disable session resumption */
             if (s->not_resumable_session_cb != NULL)
                 s->session->not_resumable =
@@ -2001,8 +1996,7 @@ int tls_construct_server_key_exchange(SSL *s, WPACKET *pkt)
     size_t encodedlen = 0;
     int curve_id = 0;
 #endif
-    EVP_PKEY *pkey;
-    const EVP_MD *md = NULL;
+    const SIGALG_LOOKUP *lu = s->s3->tmp.sigalg;
     int al = SSL_AD_INTERNAL_ERROR, i;
     unsigned long type;
     const BIGNUM *r[4];
@@ -2159,15 +2153,12 @@ int tls_construct_server_key_exchange(SSL *s, WPACKET *pkt)
         goto f_err;
     }
 
-    if (!(s->s3->tmp.new_cipher->algorithm_auth & (SSL_aNULL | SSL_aSRP))
-        && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK)) {
-        if ((pkey = ssl_get_sign_pkey(s, s->s3->tmp.new_cipher, &md))
-            == NULL) {
-            al = SSL_AD_DECODE_ERROR;
-            goto f_err;
-        }
-    } else {
-        pkey = NULL;
+    if (((s->s3->tmp.new_cipher->algorithm_auth & (SSL_aNULL | SSL_aSRP)) != 0)
+        || ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK)) != 0) {
+        lu = NULL;
+    } else if (lu == NULL) {
+        al = SSL_AD_DECODE_ERROR;
+        goto f_err;
     }
 
 #ifndef OPENSSL_NO_PSK
@@ -2257,75 +2248,66 @@ int tls_construct_server_key_exchange(SSL *s, WPACKET *pkt)
 #endif
 
     /* not anonymous */
-    if (pkey != NULL) {
+    if (lu != NULL) {
+        EVP_PKEY *pkey = s->s3->tmp.cert->privatekey;
+        const EVP_MD *md = ssl_md(lu->hash_idx);
+        unsigned char *sigbytes1, *sigbytes2;
+        size_t siglen;
+
+        if (pkey == NULL || md == NULL) {
+            /* Should never happen */
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
         /*
          * n is the length of the params, they start at &(d[4]) and p
          * points to the space at the end.
          */
-        if (md) {
-            unsigned char *sigbytes1, *sigbytes2;
-            size_t siglen;
-            int ispss = 0;
 
-            /* Get length of the parameters we have written above */
-            if (!WPACKET_get_length(pkt, &paramlen)) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                       ERR_R_INTERNAL_ERROR);
-                goto f_err;
-            }
-            /* send signature algorithm */
-            if (SSL_USE_SIGALGS(s)) {
-                if (!tls12_get_sigandhash(s, pkt, pkey, md, &ispss)) {
-                    /* Should never happen */
-                    SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                           ERR_R_INTERNAL_ERROR);
-                    goto f_err;
-                }
-            }
-#ifdef SSL_DEBUG
-            fprintf(stderr, "Using hash %s\n", EVP_MD_name(md));
-#endif
-            /*
-             * Create the signature. We don't know the actual length of the sig
-             * until after we've created it, so we reserve enough bytes for it
-             * up front, and then properly allocate them in the WPACKET
-             * afterwards.
-             */
-            siglen = EVP_PKEY_size(pkey);
-            if (!WPACKET_sub_reserve_bytes_u16(pkt, siglen, &sigbytes1)
-                    || EVP_DigestSignInit(md_ctx, &pctx, md, NULL, pkey) <= 0) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                       ERR_R_INTERNAL_ERROR);
-                goto f_err;
-            }
-            if (ispss) {
-                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) {
-                    SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                           ERR_R_EVP_LIB);
-                    goto f_err;
-                }
-            }
-            if (EVP_DigestSignUpdate(md_ctx, &(s->s3->client_random[0]),
-                                     SSL3_RANDOM_SIZE) <= 0
-                    || EVP_DigestSignUpdate(md_ctx, &(s->s3->server_random[0]),
-                                            SSL3_RANDOM_SIZE) <= 0
-                    || EVP_DigestSignUpdate(md_ctx,
-                                            s->init_buf->data + paramoffset,
-                                            paramlen) <= 0
-                    || EVP_DigestSignFinal(md_ctx, sigbytes1, &siglen) <= 0
-                    || !WPACKET_sub_allocate_bytes_u16(pkt, siglen, &sigbytes2)
-                    || sigbytes1 != sigbytes2) {
+        /* Get length of the parameters we have written above */
+        if (!WPACKET_get_length(pkt, &paramlen)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
+        /* send signature algorithm */
+        if (SSL_USE_SIGALGS(s) && !WPACKET_put_bytes_u16(pkt, lu->sigalg))
+                return 0;
+        /*
+         * Create the signature. We don't know the actual length of the sig
+         * until after we've created it, so we reserve enough bytes for it
+         * up front, and then properly allocate them in the WPACKET
+         * afterwards.
+         */
+        siglen = EVP_PKEY_size(pkey);
+        if (!WPACKET_sub_reserve_bytes_u16(pkt, siglen, &sigbytes1)
+            || EVP_DigestSignInit(md_ctx, &pctx, md, NULL, pkey) <= 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
+        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) {
                 SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                       ERR_R_INTERNAL_ERROR);
+                       ERR_R_EVP_LIB);
                 goto f_err;
             }
-        } else {
-            /* Is this error check actually needed? */
-            al = SSL_AD_HANDSHAKE_FAILURE;
+        }
+        if (EVP_DigestSignUpdate(md_ctx, &(s->s3->client_random[0]),
+                                 SSL3_RANDOM_SIZE) <= 0
+            || EVP_DigestSignUpdate(md_ctx, &(s->s3->server_random[0]),
+                                        SSL3_RANDOM_SIZE) <= 0
+            || EVP_DigestSignUpdate(md_ctx,
+                                        s->init_buf->data + paramoffset,
+                                        paramlen) <= 0
+            || EVP_DigestSignFinal(md_ctx, sigbytes1, &siglen) <= 0
+            || !WPACKET_sub_allocate_bytes_u16(pkt, siglen, &sigbytes2)
+            || sigbytes1 != sigbytes2) {
             SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                   SSL_R_UNKNOWN_PKEY_TYPE);
+                   ERR_R_INTERNAL_ERROR);
             goto f_err;
         }
     }
@@ -3215,10 +3197,9 @@ MSG_PROCESS_RETURN tls_process_client_certificate(SSL *s, PACKET *pkt)
 
 int tls_construct_server_certificate(SSL *s, WPACKET *pkt)
 {
-    CERT_PKEY *cpk;
+    CERT_PKEY *cpk = s->s3->tmp.cert;
     int al = SSL_AD_INTERNAL_ERROR;
 
-    cpk = ssl_get_server_send_pkey(s);
     if (cpk == NULL) {
         SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE, ERR_R_INTERNAL_ERROR);
         return 0;
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index eba3203..3e00cdb 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -770,6 +770,26 @@ static const SIGALG_LOOKUP sigalg_lookup_tbl[] = {
      NID_undef, NID_undef}
 #endif
 };
+/* Legacy sigalgs for TLS < 1.2 RSA TLS signatures */
+static const SIGALG_LOOKUP legacy_rsa_sigalg = {
+    "rsa_pkcs1_md5_sha1", 0,
+     NID_md5_sha1, SSL_MD_MD5_SHA1_IDX,
+     EVP_PKEY_RSA, SSL_PKEY_RSA,
+     NID_undef, NID_undef
+};
+
+/*
+ * Default signature algorithm values used if signature algorithms not present.
+ * From RFC5246. Note: order must match certificate index order.
+ */
+static const uint16_t tls_default_sigalg[] = {
+    TLSEXT_SIGALG_rsa_pkcs1_sha1, /* SSL_PKEY_RSA */
+    TLSEXT_SIGALG_dsa_sha1, /* SSL_PKEY_DSA_SIGN */
+    TLSEXT_SIGALG_ecdsa_sha1, /* SSL_PKEY_ECC */
+    TLSEXT_SIGALG_gostr34102001_gostr3411, /* SSL_PKEY_GOST01 */
+    TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256, /* SSL_PKEY_GOST12_256 */
+    TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512 /* SSL_PKEY_GOST12_512 */
+};
 
 /* Lookup TLS signature algorithm */
 static const SIGALG_LOOKUP *tls1_lookup_sigalg(uint16_t sigalg)
@@ -784,6 +804,35 @@ static const SIGALG_LOOKUP *tls1_lookup_sigalg(uint16_t sigalg)
     }
     return NULL;
 }
+/*
+ * Return a signature algorithm for TLS < 1.2 where the signature type
+ * is fixed by the certificate type.
+ */
+static const SIGALG_LOOKUP *tls1_get_legacy_sigalg(const SSL *s, int idx)
+{
+    if (idx < 0 || idx >= (int)OSSL_NELEM(tls_default_sigalg))
+        return NULL;
+    if (SSL_USE_SIGALGS(s) || idx != SSL_PKEY_RSA) {
+        const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(tls_default_sigalg[idx]);
+
+        if (lu == NULL || ssl_md(lu->hash_idx) == NULL) {
+            return NULL;
+        }
+        return lu;
+    }
+    return &legacy_rsa_sigalg;
+}
+/* Set peer sigalg based key type */
+int tls1_set_peer_legacy_sigalg(SSL *s, const EVP_PKEY *pkey)
+{
+    int idx = ssl_cert_type(NULL, pkey);
+
+    const SIGALG_LOOKUP *lu = tls1_get_legacy_sigalg(s, idx);
+    if (lu == NULL)
+        return 0;
+    s->s3->tmp.peer_sigalg = lu;
+    return 1;
+}
 
 static int tls_sigalg_get_sig(uint16_t sigalg)
 {
@@ -868,7 +917,7 @@ int tls12_check_peer_sigalg(SSL *s, uint16_t sig, EVP_PKEY *pkey)
         if (SSL_IS_TLS13(s)) {
             /* For TLS 1.3 check curve matches signature algorithm */
 
-            if (curve != lu->curve) {
+            if (lu->curve != NID_undef && curve != lu->curve) {
                 SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_WRONG_CURVE);
                 return 0;
             }
@@ -2152,8 +2201,9 @@ DH *ssl_get_auto_dh(SSL *s)
         else
             dh_secbits = 80;
     } else {
-        CERT_PKEY *cpk = ssl_get_server_send_pkey(s);
-        dh_secbits = EVP_PKEY_security_bits(cpk->privatekey);
+        if (s->s3->tmp.cert == NULL)
+            return NULL;
+        dh_secbits = EVP_PKEY_security_bits(s->s3->tmp.cert->privatekey);
     }
 
     if (dh_secbits >= 128) {
@@ -2268,8 +2318,11 @@ 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.
  */
-int tls_choose_sigalg(SSL *s)
+int tls_choose_sigalg(SSL *s, int *al)
 {
+    int idx;
+    const SIGALG_LOOKUP *lu = NULL;
+
     if (SSL_IS_TLS13(s)) {
         size_t i;
 #ifndef OPENSSL_NO_EC
@@ -2278,45 +2331,119 @@ int tls_choose_sigalg(SSL *s)
 
         /* Look for a certificate matching shared sigaglgs */
         for (i = 0; i < s->cert->shared_sigalgslen; i++) {
-            const SIGALG_LOOKUP *lu = s->cert->shared_sigalgs[i];
-            int idx;
-            const EVP_MD *md;
-            CERT_PKEY *c;
+            lu = s->cert->shared_sigalgs[i];
 
             /* Skip RSA if not PSS */
             if (lu->sig == EVP_PKEY_RSA)
                 continue;
-            md = ssl_md(lu->hash_idx);
-            if (md == NULL)
+            if (ssl_md(lu->hash_idx) == NULL)
                 continue;
             idx = lu->sig_idx;
-            c = &s->cert->pkeys[idx];
-            if (c->x509 == NULL || c->privatekey == NULL)
+            if (!ssl_has_cert(s, idx))
                     continue;
             if (lu->sig == EVP_PKEY_EC) {
 #ifndef OPENSSL_NO_EC
                 if (curve == -1) {
-                    EC_KEY *ec = EVP_PKEY_get0_EC_KEY(c->privatekey);
+                    EC_KEY *ec = EVP_PKEY_get0_EC_KEY(s->cert->pkeys[idx].privatekey);
 
                     curve = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
                 }
-                if (curve != lu->curve)
+                if (lu->curve != NID_undef && curve != lu->curve)
                     continue;
 #else
                 continue;
 #endif
             }
-            s->s3->tmp.sigalg = lu;
-            s->s3->tmp.cert_idx = idx;
-            s->s3->tmp.md[idx] = md;
-            s->cert->key = s->cert->pkeys + idx;
+            break;
+        }
+        if (i == s->cert->shared_sigalgslen) {
+            *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;
         }
-        return 0;
+        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 {
+                *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;
+        }
+
+        if (SSL_USE_SIGALGS(s)) {
+            if (s->s3->tmp.peer_sigalgs != NULL) {
+                size_t i;
+
+                /*
+                 * Find highest preference signature algorithm matching
+                 * cert type
+                 */
+                for (i = 0; i < s->cert->shared_sigalgslen; i++) {
+                    lu = s->cert->shared_sigalgs[i];
+                    if (lu->sig_idx == idx)
+                        break;
+                    if (idx == SSL_PKEY_RSA && lu->sig == EVP_PKEY_RSA_PSS)
+                        break;
+                }
+                if (i == s->cert->shared_sigalgslen) {
+                    *al = SSL_AD_INTERNAL_ERROR;
+                    SSLerr(SSL_F_TLS_CHOOSE_SIGALG, ERR_R_INTERNAL_ERROR);
+                    return 0;
+                }
+            } else {
+                /*
+                 * If we have no sigalg use defaults
+                 */
+                const uint16_t *sent_sigs;
+                size_t sent_sigslen, i;
+
+                if ((lu = tls1_get_legacy_sigalg(s, idx)) == NULL) {
+                    *al = SSL_AD_INTERNAL_ERROR;
+                    SSLerr(SSL_F_TLS_CHOOSE_SIGALG, ERR_R_INTERNAL_ERROR);
+                    return 0;
+                }
+
+                /* Check signature matches a type we sent */
+                sent_sigslen = tls12_get_psigalgs(s, 1, &sent_sigs);
+                for (i = 0; i < sent_sigslen; i++, sent_sigs++) {
+                    if (lu->sigalg == *sent_sigs)
+                        break;
+                }
+                if (i == sent_sigslen) {
+                    SSLerr(SSL_F_TLS_CHOOSE_SIGALG, SSL_R_WRONG_SIGNATURE_TYPE);
+                    *al = SSL_AD_HANDSHAKE_FAILURE;
+                    return 0;
+                }
+            }
+        } else {
+            if ((lu = tls1_get_legacy_sigalg(s, idx)) == NULL) {
+                *al = SSL_AD_INTERNAL_ERROR;
+                SSLerr(SSL_F_TLS_CHOOSE_SIGALG, ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+        }
     }
-    /*
-     * FIXME: could handle previous TLS versions in an appropriate way
-     * and tidy up certificate and signature algorithm handling.
-     */
+    s->s3->tmp.cert = &s->cert->pkeys[idx];
+    s->s3->tmp.sigalg = lu;
     return 1;
 }


More information about the openssl-commits mailing list