Use tls_choose_sigalg for client auth.
[openssl.git] / ssl / t1_lib.c
index b0df32b406a0a025fa1bed5874f76991ad15d7df..fc9ae687f605152794bcde22e678e106cec9b20a 100644 (file)
@@ -607,7 +607,7 @@ static int tls1_check_cert_param(SSL *s, X509 *x, int set_ee_md)
         else
             return 0;           /* Should never happen */
         for (i = 0; i < c->shared_sigalgslen; i++)
-            if (check_md == c->shared_sigalgs[i].signandhash_nid)
+            if (check_md == c->shared_sigalgs[i]->sigandhash)
                 break;
         if (i == c->shared_sigalgslen)
             return 0;
@@ -670,7 +670,7 @@ static int tls1_check_cert_param(SSL *s, X509 *x, int set_ee_md)
 #endif                          /* OPENSSL_NO_EC */
 
 /* Default sigalg schemes */
-static const unsigned int tls12_sigalgs[] = {
+static const uint16_t tls12_sigalgs[] = {
 #ifndef OPENSSL_NO_EC
     TLSEXT_SIGALG_ecdsa_secp256r1_sha256,
     TLSEXT_SIGALG_ecdsa_secp384r1_sha384,
@@ -699,77 +699,149 @@ static const unsigned int tls12_sigalgs[] = {
 };
 
 #ifndef OPENSSL_NO_EC
-static const unsigned int suiteb_sigalgs[] = {
+static const uint16_t suiteb_sigalgs[] = {
     TLSEXT_SIGALG_ecdsa_secp256r1_sha256,
     TLSEXT_SIGALG_ecdsa_secp384r1_sha384
 };
 #endif
 
-typedef struct sigalg_lookup_st {
-    unsigned int sigalg;
-    int hash;
-    int sig;
-} SIGALG_LOOKUP;
-
 static const SIGALG_LOOKUP sigalg_lookup_tbl[] = {
 #ifndef OPENSSL_NO_EC
-    {TLSEXT_SIGALG_ecdsa_secp256r1_sha256, NID_sha256, EVP_PKEY_EC},
-    {TLSEXT_SIGALG_ecdsa_secp384r1_sha384, NID_sha384, EVP_PKEY_EC},
-    {TLSEXT_SIGALG_ecdsa_secp521r1_sha512, NID_sha512, EVP_PKEY_EC},
-    {TLSEXT_SIGALG_ecdsa_sha1, NID_sha1, EVP_PKEY_EC},
+    {"ecdsa_secp256r1_sha256", TLSEXT_SIGALG_ecdsa_secp256r1_sha256,
+     NID_sha256, SSL_MD_SHA256_IDX, EVP_PKEY_EC, SSL_PKEY_ECC,
+     NID_ecdsa_with_SHA256, NID_X9_62_prime256v1},
+    {"ecdsa_secp384r1_sha384", TLSEXT_SIGALG_ecdsa_secp384r1_sha384,
+     NID_sha384, SSL_MD_SHA384_IDX, EVP_PKEY_EC, SSL_PKEY_ECC,
+     NID_ecdsa_with_SHA384, NID_secp384r1},
+    {"ecdsa_secp521r1_sha512", TLSEXT_SIGALG_ecdsa_secp521r1_sha512,
+     NID_sha512, SSL_MD_SHA512_IDX, EVP_PKEY_EC, SSL_PKEY_ECC,
+     NID_ecdsa_with_SHA512, NID_secp521r1},
+    {NULL, TLSEXT_SIGALG_ecdsa_sha1,
+     NID_sha1, SSL_MD_SHA1_IDX, EVP_PKEY_EC, SSL_PKEY_ECC,
+     NID_ecdsa_with_SHA1, NID_undef},
 #endif
-    /*
-     * PSS must appear before PKCS1 so that we prefer that when signing where
-     * possible
-     */
-    {TLSEXT_SIGALG_rsa_pss_sha256, NID_sha256, EVP_PKEY_RSA},
-    {TLSEXT_SIGALG_rsa_pss_sha384, NID_sha384, EVP_PKEY_RSA},
-    {TLSEXT_SIGALG_rsa_pss_sha512, NID_sha512, EVP_PKEY_RSA},
-    {TLSEXT_SIGALG_rsa_pkcs1_sha256, NID_sha256, EVP_PKEY_RSA},
-    {TLSEXT_SIGALG_rsa_pkcs1_sha384, NID_sha384, EVP_PKEY_RSA},
-    {TLSEXT_SIGALG_rsa_pkcs1_sha512, NID_sha512, EVP_PKEY_RSA},
-    {TLSEXT_SIGALG_rsa_pkcs1_sha1, NID_sha1, EVP_PKEY_RSA},
+    {"rsa_pss_sha256", TLSEXT_SIGALG_rsa_pss_sha256,
+     NID_sha256, SSL_MD_SHA256_IDX, EVP_PKEY_RSA_PSS, SSL_PKEY_RSA_PSS_SIGN,
+     NID_undef, NID_undef},
+    {"rsa_pss_sha384", TLSEXT_SIGALG_rsa_pss_sha384,
+     NID_sha384, SSL_MD_SHA384_IDX, EVP_PKEY_RSA_PSS, SSL_PKEY_RSA_PSS_SIGN,
+     NID_undef, NID_undef},
+    {"rsa_pss_sha512", TLSEXT_SIGALG_rsa_pss_sha512,
+     NID_sha512, SSL_MD_SHA512_IDX, EVP_PKEY_RSA_PSS, SSL_PKEY_RSA_PSS_SIGN,
+     NID_undef, NID_undef},
+    {"rsa_pkcs1_sha256", TLSEXT_SIGALG_rsa_pkcs1_sha256,
+     NID_sha256, SSL_MD_SHA256_IDX, EVP_PKEY_RSA, SSL_PKEY_RSA,
+     NID_sha256WithRSAEncryption, NID_undef},
+    {"rsa_pkcs1_sha384", TLSEXT_SIGALG_rsa_pkcs1_sha384,
+     NID_sha384, SSL_MD_SHA384_IDX, EVP_PKEY_RSA, SSL_PKEY_RSA,
+     NID_sha384WithRSAEncryption, NID_undef},
+    {"rsa_pkcs1_sha512", TLSEXT_SIGALG_rsa_pkcs1_sha512,
+     NID_sha512, SSL_MD_SHA512_IDX, EVP_PKEY_RSA, SSL_PKEY_RSA,
+     NID_sha512WithRSAEncryption, NID_undef},
+    {"rsa_pkcs1_sha1", TLSEXT_SIGALG_rsa_pkcs1_sha1,
+     NID_sha1, SSL_MD_SHA1_IDX, EVP_PKEY_RSA, SSL_PKEY_RSA,
+     NID_sha1WithRSAEncryption, NID_undef},
 #ifndef OPENSSL_NO_DSA
-    {TLSEXT_SIGALG_dsa_sha256, NID_sha256, EVP_PKEY_DSA},
-    {TLSEXT_SIGALG_dsa_sha384, NID_sha384, EVP_PKEY_DSA},
-    {TLSEXT_SIGALG_dsa_sha512, NID_sha512, EVP_PKEY_DSA},
-    {TLSEXT_SIGALG_dsa_sha1, NID_sha1, EVP_PKEY_DSA},
+    {NULL, TLSEXT_SIGALG_dsa_sha256,
+     NID_sha256, SSL_MD_SHA256_IDX, EVP_PKEY_DSA, SSL_PKEY_DSA_SIGN,
+     NID_dsa_with_SHA256, NID_undef},
+    {NULL, TLSEXT_SIGALG_dsa_sha384,
+     NID_sha384, SSL_MD_SHA384_IDX, EVP_PKEY_DSA, SSL_PKEY_DSA_SIGN,
+     NID_undef, NID_undef},
+    {NULL, TLSEXT_SIGALG_dsa_sha512,
+     NID_sha512, SSL_MD_SHA512_IDX, EVP_PKEY_DSA, SSL_PKEY_DSA_SIGN,
+     NID_undef, NID_undef},
+    {NULL, TLSEXT_SIGALG_dsa_sha1,
+     NID_sha1, SSL_MD_SHA1_IDX, EVP_PKEY_DSA, SSL_PKEY_DSA_SIGN,
+     NID_dsaWithSHA1, NID_undef},
 #endif
 #ifndef OPENSSL_NO_GOST
-    {TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256, NID_id_GostR3411_2012_256, NID_id_GostR3410_2012_256},
-    {TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512, NID_id_GostR3411_2012_512, NID_id_GostR3410_2012_512},
-    {TLSEXT_SIGALG_gostr34102001_gostr3411, NID_id_GostR3411_94, NID_id_GostR3410_2001}
+    {NULL, TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256,
+     NID_id_GostR3411_2012_256, SSL_MD_GOST12_256_IDX,
+     NID_id_GostR3410_2012_256, SSL_PKEY_GOST12_256,
+     NID_undef, NID_undef},
+    {NULL, TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512,
+     NID_id_GostR3411_2012_512, SSL_MD_GOST12_512_IDX,
+     NID_id_GostR3410_2012_512, SSL_PKEY_GOST12_512,
+     NID_undef, NID_undef},
+    {NULL, TLSEXT_SIGALG_gostr34102001_gostr3411,
+     NID_id_GostR3411_94, SSL_MD_GOST94_IDX,
+     NID_id_GostR3410_2001, SSL_PKEY_GOST01,
+     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 */
+};
 
-static int tls_sigalg_get_hash(unsigned int sigalg)
+/* Lookup TLS signature algorithm */
+static const SIGALG_LOOKUP *tls1_lookup_sigalg(uint16_t sigalg)
 {
     size_t i;
-    const SIGALG_LOOKUP *curr;
+    const SIGALG_LOOKUP *s;
 
-    for (i = 0, curr = sigalg_lookup_tbl; i < OSSL_NELEM(sigalg_lookup_tbl);
-         i++, curr++) {
-        if (curr->sigalg == sigalg)
-            return curr->hash;
+    for (i = 0, s = sigalg_lookup_tbl; i < OSSL_NELEM(sigalg_lookup_tbl);
+         i++, s++) {
+        if (s->sigalg == sigalg)
+            return s;
     }
-
-    return 0;
+    return NULL;
 }
-
-static int tls_sigalg_get_sig(unsigned int sigalg)
+/*
+ * 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)
 {
-    size_t i;
-    const SIGALG_LOOKUP *curr;
+    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]);
 
-    for (i = 0, curr = sigalg_lookup_tbl; i < OSSL_NELEM(sigalg_lookup_tbl);
-         i++, curr++) {
-        if (curr->sigalg == sigalg)
-            return curr->sig;
+        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);
 
-    return 0;
+    const SIGALG_LOOKUP *lu = tls1_get_legacy_sigalg(s, idx);
+    if (lu == NULL)
+        return 0;
+    s->s3->tmp.peer_sigalg = lu;
+    return 1;
 }
-size_t tls12_get_psigalgs(SSL *s, int sent, const unsigned int **psigs)
+
+static int tls_sigalg_get_sig(uint16_t sigalg)
+{
+    const SIGALG_LOOKUP *r = tls1_lookup_sigalg(sigalg);
+
+    return r != NULL ? r->sig : 0;
+}
+
+size_t tls12_get_psigalgs(SSL *s, int sent, const uint16_t **psigs)
 {
     /*
      * If Suite B mode use Suite B sigalgs only, ignore any other
@@ -809,54 +881,80 @@ size_t tls12_get_psigalgs(SSL *s, int sent, const unsigned int **psigs)
 
 /*
  * Check signature algorithm is consistent with sent supported signature
- * algorithms and if so return relevant digest.
+ * algorithms and if so set relevant digest and signature scheme in
+ * s.
  */
-int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s, unsigned int sig,
-                            EVP_PKEY *pkey)
+int tls12_check_peer_sigalg(SSL *s, uint16_t sig, EVP_PKEY *pkey)
 {
-    const unsigned int *sent_sigs;
+    const uint16_t *sent_sigs;
+    const EVP_MD *md = NULL;
     char sigalgstr[2];
     size_t sent_sigslen, i;
     int pkeyid = EVP_PKEY_id(pkey);
+    const SIGALG_LOOKUP *lu;
+
     /* Should never happen */
     if (pkeyid == -1)
         return -1;
-    /* Check key type is consistent with signature */
-    if (pkeyid != tls_sigalg_get_sig(sig)) {
+    /* Only allow PSS for TLS 1.3 */
+    if (SSL_IS_TLS13(s) && pkeyid == EVP_PKEY_RSA)
+        pkeyid = EVP_PKEY_RSA_PSS;
+    lu = tls1_lookup_sigalg(sig);
+    /*
+     * Check sigalgs is known and key type is consistent with signature:
+     * RSA keys can be used for RSA-PSS
+     */
+    if (lu == NULL || (pkeyid != lu->sig
+        && (lu->sig != EVP_PKEY_RSA_PSS || pkeyid != EVP_PKEY_RSA))) {
         SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_WRONG_SIGNATURE_TYPE);
         return 0;
     }
 #ifndef OPENSSL_NO_EC
     if (pkeyid == EVP_PKEY_EC) {
-        unsigned char curve_id[2], comp_id;
-        /* Check compression and curve matches extensions */
-        if (!tls1_set_ec_id(curve_id, &comp_id, EVP_PKEY_get0_EC_KEY(pkey)))
-            return 0;
-        if (!s->server && !tls1_check_ec_key(s, curve_id, &comp_id)) {
-            SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_WRONG_CURVE);
-            return 0;
-        }
-        /* If Suite B only P-384+SHA384 or P-256+SHA-256 allowed */
-        if (tls1_suiteb(s)) {
-            if (curve_id[0])
+        EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey);
+        int curve = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
+
+        if (SSL_IS_TLS13(s)) {
+            /* For TLS 1.3 check curve matches signature algorithm */
+
+            if (lu->curve != NID_undef && curve != lu->curve) {
+                SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_WRONG_CURVE);
                 return 0;
-            if (curve_id[1] == TLSEXT_curve_P_256) {
-                if (tls_sigalg_get_hash(sig) != NID_sha256) {
+            }
+        } else {
+            unsigned char curve_id[2], comp_id;
+
+            /* Check compression and curve matches extensions */
+            if (!tls1_set_ec_id(curve_id, &comp_id, ec))
+                return 0;
+            if (!s->server && !tls1_check_ec_key(s, curve_id, &comp_id)) {
+                SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_WRONG_CURVE);
+                return 0;
+            }
+            if (tls1_suiteb(s)) {
+                /* Check sigalg matches a permissible Suite B value */
+                if (sig != TLSEXT_SIGALG_ecdsa_secp256r1_sha256
+                    && sig != TLSEXT_SIGALG_ecdsa_secp384r1_sha384) {
                     SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,
-                           SSL_R_ILLEGAL_SUITEB_DIGEST);
+                           SSL_R_WRONG_SIGNATURE_TYPE);
                     return 0;
                 }
-            } else if (curve_id[1] == TLSEXT_curve_P_384) {
-                if (tls_sigalg_get_hash(sig) != NID_sha384) {
+                /*
+                 * Suite B also requires P-256+SHA256 and P-384+SHA384:
+                 * this matches the TLS 1.3 requirements so we can just
+                 * check the curve is the expected TLS 1.3 value.
+                 * If this fails an inappropriate digest is being used.
+                 */
+                if (curve != lu->curve) {
                     SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,
                            SSL_R_ILLEGAL_SUITEB_DIGEST);
                     return 0;
                 }
-            } else
-                return 0;
+            }
         }
-    } else if (tls1_suiteb(s))
+    } else if (tls1_suiteb(s)) {
         return 0;
+    }
 #endif
 
     /* Check signature matches a type we sent */
@@ -866,14 +964,13 @@ int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s, unsigned int sig,
             break;
     }
     /* Allow fallback to SHA1 if not strict mode */
-    if (i == sent_sigslen
-        && (tls_sigalg_get_hash(sig) != NID_sha1
-            || s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT)) {
+    if (i == sent_sigslen && (lu->hash != NID_sha1
+        || s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT)) {
         SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_WRONG_SIGNATURE_TYPE);
         return 0;
     }
-    *pmd = tls12_get_hash(tls_sigalg_get_hash(sig));
-    if (*pmd == NULL) {
+    md = ssl_md(lu->hash_idx);
+    if (md == NULL) {
         SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_UNKNOWN_DIGEST);
         return 0;
     }
@@ -884,15 +981,21 @@ int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s, unsigned int sig,
     sigalgstr[0] = (sig >> 8) & 0xff;
     sigalgstr[1] = sig & 0xff;
     if (!ssl_security(s, SSL_SECOP_SIGALG_CHECK,
-                      EVP_MD_size(*pmd) * 4, EVP_MD_type(*pmd),
+                      EVP_MD_size(md) * 4, EVP_MD_type(md),
                       (void *)sigalgstr)) {
         SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_WRONG_SIGNATURE_TYPE);
         return 0;
     }
-    /*
-     * Store the digest used so applications can retrieve it if they wish.
-     */
-    s->s3->tmp.peer_md = *pmd;
+    /* Store the sigalg the peer uses */
+    s->s3->tmp.peer_sigalg = lu;
+    return 1;
+}
+
+int SSL_get_peer_signature_type_nid(const SSL *s, int *pnid)
+{
+    if (s->s3->tmp.peer_sigalg == NULL)
+        return 0;
+    *pnid = s->s3->tmp.peer_sigalg->sig;
     return 1;
 }
 
@@ -968,10 +1071,9 @@ void ssl_set_default_md(SSL *s)
 #endif
 #ifndef OPENSSL_NO_RSA
     if (SSL_USE_SIGALGS(s))
-        pmd[SSL_PKEY_RSA_SIGN] = ssl_md(SSL_MD_SHA1_IDX);
+        pmd[SSL_PKEY_RSA] = ssl_md(SSL_MD_SHA1_IDX);
     else
-        pmd[SSL_PKEY_RSA_SIGN] = ssl_md(SSL_MD_MD5_SHA1_IDX);
-    pmd[SSL_PKEY_RSA_ENC] = pmd[SSL_PKEY_RSA_SIGN];
+        pmd[SSL_PKEY_RSA] = ssl_md(SSL_MD_MD5_SHA1_IDX);
 #endif
 #ifndef OPENSSL_NO_EC
     pmd[SSL_PKEY_ECC] = ssl_md(SSL_MD_SHA1_IDX);
@@ -1049,8 +1151,8 @@ int tls1_set_server_sigalgs(SSL *s)
  *   s->ctx->ext.ticket_key_cb asked to renew the client's ticket.
  *   Otherwise, s->ext.ticket_expected is set to 0.
  */
-int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
-                               SSL_SESSION **ret)
+TICKET_RETURN tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
+                                         SSL_SESSION **ret)
 {
     int retv;
     size_t size;
@@ -1065,11 +1167,11 @@ int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
      * resumption.
      */
     if (s->version <= SSL3_VERSION || !tls_use_ticket(s))
-        return 0;
+        return TICKET_NONE;
 
     ticketext = &hello->pre_proc_exts[TLSEXT_IDX_session_ticket];
     if (!ticketext->present)
-        return 0;
+        return TICKET_NONE;
 
     size = PACKET_remaining(&ticketext->data);
     if (size == 0) {
@@ -1078,7 +1180,7 @@ int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
          * one.
          */
         s->ext.ticket_expected = 1;
-        return 1;
+        return TICKET_EMPTY;
     }
     if (s->ext.session_secret_cb) {
         /*
@@ -1087,25 +1189,25 @@ int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
          * abbreviated handshake based on external mechanism to
          * calculate the master secret later.
          */
-        return 2;
+        return TICKET_NO_DECRYPT;
     }
 
     retv = tls_decrypt_ticket(s, PACKET_data(&ticketext->data), size,
                               hello->session_id, hello->session_id_len, ret);
     switch (retv) {
-    case TICKET_NO_DECRYPT: /* ticket couldn't be decrypted */
+    case TICKET_NO_DECRYPT:
         s->ext.ticket_expected = 1;
-        return 2;
+        return TICKET_NO_DECRYPT;
 
-    case TICKET_SUCCESS: /* ticket was decrypted */
-        return 3;
+    case TICKET_SUCCESS:
+        return TICKET_SUCCESS;
 
-    case TICKET_SUCCESS_RENEW: /* ticket decrypted but need to renew */
+    case TICKET_SUCCESS_RENEW:
         s->ext.ticket_expected = 1;
-        return 3;
+        return TICKET_SUCCESS;
 
-    default:           /* fatal error */
-        return -1;
+    default:
+        return TICKET_FATAL_ERR_OTHER;
     }
 }
 
@@ -1118,34 +1220,21 @@ int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
  *   sesslen: the length of the session ID.
  *   psess: (output) on return, if a ticket was decrypted, then this is set to
  *       point to the resulting session.
- *
- * Returns:
- *   TICKET_FATAL_ERR_MALLOC: fatal error, malloc failure.
- *   TICKET_FATAL_ERR_OTHER:  fatal error, either from parsing or decrypting the
- *                            ticket.
- *   TICKET_NO_DECRYPT:       the ticket couldn't be decrypted.
- *   TICKET_SUCCESS:          a ticket was successfully decrypted and *psess was
- *                            set.
- *   TICKET_SUCCESS_RENEW:    same as 3, but the ticket needs to be renewed
  */
-#define TICKET_FATAL_ERR_MALLOC     -2
-#define TICKET_FATAL_ERR_OTHER      -1
-#define TICKET_NO_DECRYPT            2
-#define TICKET_SUCCESS               3
-#define TICKET_SUCCESS_RENEW         4
-int tls_decrypt_ticket(SSL *s, const unsigned char *etick, size_t eticklen,
-                       const unsigned char *sess_id, size_t sesslen,
-                       SSL_SESSION **psess)
+TICKET_RETURN tls_decrypt_ticket(SSL *s, const unsigned char *etick,
+                                 size_t eticklen, const unsigned char *sess_id,
+                                 size_t sesslen, SSL_SESSION **psess)
 {
     SSL_SESSION *sess;
     unsigned char *sdec;
     const unsigned char *p;
-    int slen, renew_ticket = 0, ret = TICKET_FATAL_ERR_OTHER, declen;
+    int slen, renew_ticket = 0, declen;
+    TICKET_RETURN ret = TICKET_FATAL_ERR_OTHER;
     size_t mlen;
     unsigned char tick_hmac[EVP_MAX_MD_SIZE];
     HMAC_CTX *hctx = NULL;
     EVP_CIPHER_CTX *ctx;
-    SSL_CTX *tctx = s->initial_ctx;
+    SSL_CTX *tctx = s->session_ctx;
 
     /* Initialize session ticket encryption and HMAC contexts */
     hctx = HMAC_CTX_new();
@@ -1212,8 +1301,8 @@ int tls_decrypt_ticket(SSL *s, const unsigned char *etick, size_t eticklen,
     }
     /* Attempt to decrypt session data */
     /* Move p after IV to start of encrypted ticket, update length */
-    p = etick + 16 + EVP_CIPHER_CTX_iv_length(ctx);
-    eticklen -= 16 + EVP_CIPHER_CTX_iv_length(ctx);
+    p = etick + TLSEXT_KEYNAME_LENGTH + EVP_CIPHER_CTX_iv_length(ctx);
+    eticklen -= TLSEXT_KEYNAME_LENGTH + EVP_CIPHER_CTX_iv_length(ctx);
     sdec = OPENSSL_malloc(eticklen);
     if (sdec == NULL || EVP_DecryptUpdate(ctx, sdec, &slen, p,
                                           (int)eticklen) <= 0) {
@@ -1260,99 +1349,18 @@ int tls_decrypt_ticket(SSL *s, const unsigned char *etick, size_t eticklen,
     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, tmpispss = 0;
-    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 (i = 0, curr = sigalg_lookup_tbl; i < OSSL_NELEM(sigalg_lookup_tbl);
-         i++, curr++) {
-        if (curr->hash == md_id && curr->sig == sig_id) {
-            if (sig_id == EVP_PKEY_RSA) {
-                tmpispss = SIGID_IS_PSS(curr->sigalg);
-                if (!SSL_IS_TLS13(s) && tmpispss) {
-                    size_t j;
-
-                    /*
-                     * Check peer actually sent a PSS sig id - it could have
-                     * been a PKCS1 sig id instead.
-                     */
-                    for (j = 0; j < s->cert->shared_sigalgslen; j++)
-                        if (s->cert->shared_sigalgs[j].rsigalg == curr->sigalg)
-                            break;
-
-                    if (j == s->cert->shared_sigalgslen)
-                        continue;
-                }
-            }
-            if (!WPACKET_put_bytes_u16(pkt, curr->sigalg))
-                return 0;
-            *ispss = tmpispss;
-            return 1;
-        }
-    }
-
-    return 0;
-}
-
-typedef struct {
-    int nid;
-    int secbits;
-    int md_idx;
-} tls12_hash_info;
-
-static const tls12_hash_info tls12_md_info[] = {
-    {NID_md5, 64, SSL_MD_MD5_IDX},
-    {NID_sha1, 80, SSL_MD_SHA1_IDX},
-    {NID_sha224, 112, SSL_MD_SHA224_IDX},
-    {NID_sha256, 128, SSL_MD_SHA256_IDX},
-    {NID_sha384, 192, SSL_MD_SHA384_IDX},
-    {NID_sha512, 256, SSL_MD_SHA512_IDX},
-    {NID_id_GostR3411_94, 128, SSL_MD_GOST94_IDX},
-    {NID_id_GostR3411_2012_256, 128, SSL_MD_GOST12_256_IDX},
-    {NID_id_GostR3411_2012_512, 256, SSL_MD_GOST12_512_IDX},
-};
-
-static const tls12_hash_info *tls12_get_hash_info(int hash_nid)
-{
-    unsigned int i;
-    if (hash_nid == NID_undef)
-        return NULL;
-
-    for (i = 0; i < OSSL_NELEM(tls12_md_info); i++) {
-        if (tls12_md_info[i].nid == hash_nid)
-            return tls12_md_info + i;
-    }
-
-    return NULL;
-}
-
-const EVP_MD *tls12_get_hash(int hash_nid)
-{
-    const tls12_hash_info *inf;
-    if (hash_nid == NID_md5 && FIPS_mode())
-        return NULL;
-    inf = tls12_get_hash_info(hash_nid);
-    if (!inf)
-        return NULL;
-    return ssl_md(inf->md_idx);
-}
-
 static int tls12_get_pkey_idx(int sig_nid)
 {
     switch (sig_nid) {
 #ifndef OPENSSL_NO_RSA
     case EVP_PKEY_RSA:
-        return SSL_PKEY_RSA_SIGN;
+        return SSL_PKEY_RSA;
+    /*
+     * For now return RSA key for PSS. When we support PSS only keys
+     * this will need to be updated.
+     */
+    case EVP_PKEY_RSA_PSS:
+        return SSL_PKEY_RSA;
 #endif
 #ifndef OPENSSL_NO_DSA
     case EVP_PKEY_DSA:
@@ -1376,47 +1384,25 @@ static int tls12_get_pkey_idx(int sig_nid)
     return -1;
 }
 
-/* Convert TLS 1.2 signature algorithm extension values into NIDs */
-static void tls1_lookup_sigalg(int *phash_nid, int *psign_nid,
-                               int *psignhash_nid, unsigned int data)
-{
-    int sign_nid = NID_undef, hash_nid = NID_undef;
-    if (!phash_nid && !psign_nid && !psignhash_nid)
-        return;
-    if (phash_nid || psignhash_nid) {
-        hash_nid = tls_sigalg_get_hash(data);
-        if (phash_nid)
-            *phash_nid = hash_nid;
-    }
-    if (psign_nid || psignhash_nid) {
-        sign_nid = tls_sigalg_get_sig(data);
-        if (psign_nid)
-            *psign_nid = sign_nid;
-    }
-    if (psignhash_nid) {
-        if (sign_nid == NID_undef || hash_nid == NID_undef
-            || OBJ_find_sigid_by_algs(psignhash_nid, hash_nid, sign_nid) <= 0)
-            *psignhash_nid = NID_undef;
-    }
-}
-
 /* Check to see if a signature algorithm is allowed */
-static int tls12_sigalg_allowed(SSL *s, int op, unsigned int ptmp)
+static int tls12_sigalg_allowed(SSL *s, int op, uint16_t ptmp)
 {
-    /* See if we have an entry in the hash table and it is enabled */
-    const tls12_hash_info *hinf
-        = tls12_get_hash_info(tls_sigalg_get_hash(ptmp));
+    const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(ptmp);
     unsigned char sigalgstr[2];
+    int secbits;
 
-    if (hinf == NULL || ssl_md(hinf->md_idx) == NULL)
+    /* See if sigalgs is recognised and if hash is enabled */
+    if (lu == NULL || ssl_md(lu->hash_idx) == NULL)
         return 0;
     /* See if public key algorithm allowed */
-    if (tls12_get_pkey_idx(tls_sigalg_get_sig(ptmp)) == -1)
+    if (tls12_get_pkey_idx(lu->sig) == -1)
         return 0;
+    /* Security bits: half digest bits */
+    secbits = EVP_MD_size(ssl_md(lu->hash_idx)) * 4;
     /* Finally see if security callback allows it */
     sigalgstr[0] = (ptmp >> 8) & 0xff;
     sigalgstr[1] = ptmp & 0xff;
-    return ssl_security(s, op, hinf->secbits, hinf->nid, (void *)sigalgstr);
+    return ssl_security(s, op, secbits, lu->hash, (void *)sigalgstr);
 }
 
 /*
@@ -1427,7 +1413,7 @@ static int tls12_sigalg_allowed(SSL *s, int op, unsigned int ptmp)
 
 void ssl_set_sig_mask(uint32_t *pmask_a, SSL *s, int op)
 {
-    const unsigned int *sigalgs;
+    const uint16_t *sigalgs;
     size_t i, sigalgslen;
     int have_rsa = 0, have_dsa = 0, have_ecdsa = 0;
     /*
@@ -1439,6 +1425,8 @@ void ssl_set_sig_mask(uint32_t *pmask_a, SSL *s, int op)
     for (i = 0; i < sigalgslen; i ++, sigalgs++) {
         switch (tls_sigalg_get_sig(*sigalgs)) {
 #ifndef OPENSSL_NO_RSA
+        /* Any RSA-PSS signature algorithms also mean we allow RSA */
+        case EVP_PKEY_RSA_PSS:
         case EVP_PKEY_RSA:
             if (!have_rsa && tls12_sigalg_allowed(s, op, *sigalgs))
                 have_rsa = 1;
@@ -1467,7 +1455,7 @@ void ssl_set_sig_mask(uint32_t *pmask_a, SSL *s, int op)
 }
 
 int tls12_copy_sigalgs(SSL *s, WPACKET *pkt,
-                       const unsigned int *psig, size_t psiglen)
+                       const uint16_t *psig, size_t psiglen)
 {
     size_t i;
 
@@ -1481,11 +1469,11 @@ int tls12_copy_sigalgs(SSL *s, WPACKET *pkt,
 }
 
 /* Given preference and allowed sigalgs set shared sigalgs */
-static size_t tls12_shared_sigalgs(SSL *s, TLS_SIGALGS *shsig,
-                                   const unsigned int *pref, size_t preflen,
-                                   const unsigned int *allow, size_t allowlen)
+static size_t tls12_shared_sigalgs(SSL *s, const SIGALG_LOOKUP **shsig,
+                                   const uint16_t *pref, size_t preflen,
+                                   const uint16_t *allow, size_t allowlen)
 {
-    const unsigned int *ptmp, *atmp;
+    const uint16_t *ptmp, *atmp;
     size_t i, j, nmatch = 0;
     for (i = 0, ptmp = pref; i < preflen; i++, ptmp++) {
         /* Skip disabled hashes or signature algorithms */
@@ -1495,10 +1483,7 @@ static size_t tls12_shared_sigalgs(SSL *s, TLS_SIGALGS *shsig,
             if (*ptmp == *atmp) {
                 nmatch++;
                 if (shsig) {
-                    shsig->rsigalg = *ptmp;
-                    tls1_lookup_sigalg(&shsig->hash_nid,
-                                       &shsig->sign_nid,
-                                       &shsig->signandhash_nid, *ptmp);
+                    *shsig = tls1_lookup_sigalg(*ptmp);
                     shsig++;
                 }
                 break;
@@ -1511,10 +1496,10 @@ static size_t tls12_shared_sigalgs(SSL *s, TLS_SIGALGS *shsig,
 /* Set shared signature algorithms for SSL structures */
 static int tls1_set_shared_sigalgs(SSL *s)
 {
-    const unsigned int *pref, *allow, *conf;
+    const uint16_t *pref, *allow, *conf;
     size_t preflen, allowlen, conflen;
     size_t nmatch;
-    TLS_SIGALGS *salgs = NULL;
+    const SIGALG_LOOKUP **salgs = NULL;
     CERT *c = s->cert;
     unsigned int is_suiteb = tls1_suiteb(s);
 
@@ -1543,7 +1528,7 @@ static int tls1_set_shared_sigalgs(SSL *s)
     }
     nmatch = tls12_shared_sigalgs(s, NULL, pref, preflen, allow, allowlen);
     if (nmatch) {
-        salgs = OPENSSL_malloc(nmatch * sizeof(TLS_SIGALGS));
+        salgs = OPENSSL_malloc(nmatch * sizeof(*salgs));
         if (salgs == NULL)
             return 0;
         nmatch = tls12_shared_sigalgs(s, salgs, pref, preflen, allow, allowlen);
@@ -1560,6 +1545,7 @@ static int tls1_set_shared_sigalgs(SSL *s)
 int tls1_save_sigalgs(SSL *s, PACKET *pkt)
 {
     CERT *c = s->cert;
+    unsigned int stmp;
     size_t size, i;
 
     /* Extension ignored for inappropriate versions */
@@ -1583,9 +1569,8 @@ int tls1_save_sigalgs(SSL *s, PACKET *pkt)
     if (s->s3->tmp.peer_sigalgs == NULL)
         return 0;
     s->s3->tmp.peer_sigalgslen = size;
-    for (i = 0; i < size && PACKET_get_net_2(pkt, &s->s3->tmp.peer_sigalgs[i]);
-         i++)
-        continue;
+    for (i = 0; i < size && PACKET_get_net_2(pkt, &stmp); i++)
+        s->s3->tmp.peer_sigalgs[i] = stmp;
 
     if (i != size)
         return 0;
@@ -1601,30 +1586,22 @@ int tls1_process_sigalgs(SSL *s)
     const EVP_MD **pmd = s->s3->tmp.md;
     uint32_t *pvalid = s->s3->tmp.valid_flags;
     CERT *c = s->cert;
-    TLS_SIGALGS *sigptr;
+
     if (!tls1_set_shared_sigalgs(s))
         return 0;
 
-    for (i = 0, sigptr = c->shared_sigalgs;
-         i < c->shared_sigalgslen; i++, sigptr++) {
+    for (i = 0; i < c->shared_sigalgslen; i++) {
+        const SIGALG_LOOKUP *sigptr = c->shared_sigalgs[i];
+
         /* Ignore PKCS1 based sig algs in TLSv1.3 */
-        if (SSL_IS_TLS13(s)
-                && (sigptr->rsigalg == TLSEXT_SIGALG_rsa_pkcs1_sha1
-                    || sigptr->rsigalg == TLSEXT_SIGALG_rsa_pkcs1_sha256
-                    || sigptr->rsigalg == TLSEXT_SIGALG_rsa_pkcs1_sha384
-                    || sigptr->rsigalg == TLSEXT_SIGALG_rsa_pkcs1_sha512))
+        if (SSL_IS_TLS13(s) && sigptr->sig == EVP_PKEY_RSA)
             continue;
-        idx = tls12_get_pkey_idx(sigptr->sign_nid);
-        if (idx > 0 && pmd[idx] == NULL) {
-            md = tls12_get_hash(sigptr->hash_nid);
+        idx = tls12_get_pkey_idx(sigptr->sig);
+        if (idx >= 0 && pmd[idx] == NULL) {
+            md = ssl_md(sigptr->hash_idx);
             pmd[idx] = md;
             pvalid[idx] = CERT_PKEY_EXPLICIT_SIGN;
-            if (idx == SSL_PKEY_RSA_SIGN) {
-                pvalid[SSL_PKEY_RSA_ENC] = CERT_PKEY_EXPLICIT_SIGN;
-                pmd[SSL_PKEY_RSA_ENC] = md;
-            }
         }
-
     }
     /*
      * In strict mode or TLS1.3 leave unset digests as NULL to indicate we can't
@@ -1641,9 +1618,8 @@ int tls1_process_sigalgs(SSL *s)
             pmd[SSL_PKEY_DSA_SIGN] = EVP_sha1();
 #endif
 #ifndef OPENSSL_NO_RSA
-        if (pmd[SSL_PKEY_RSA_SIGN] == NULL) {
-            pmd[SSL_PKEY_RSA_SIGN] = EVP_sha1();
-            pmd[SSL_PKEY_RSA_ENC] = EVP_sha1();
+        if (pmd[SSL_PKEY_RSA] == NULL) {
+            pmd[SSL_PKEY_RSA] = EVP_sha1();
         }
 #endif
 #ifndef OPENSSL_NO_EC
@@ -1668,19 +1644,27 @@ int SSL_get_sigalgs(SSL *s, int idx,
                     int *psign, int *phash, int *psignhash,
                     unsigned char *rsig, unsigned char *rhash)
 {
-    unsigned int *psig = s->s3->tmp.peer_sigalgs;
+    uint16_t *psig = s->s3->tmp.peer_sigalgs;
     size_t numsigalgs = s->s3->tmp.peer_sigalgslen;
     if (psig == NULL || numsigalgs > INT_MAX)
         return 0;
     if (idx >= 0) {
+        const SIGALG_LOOKUP *lu;
+
         if (idx >= (int)numsigalgs)
             return 0;
         psig += idx;
-        if (rhash)
+        if (rhash != NULL)
             *rhash = (unsigned char)((*psig >> 8) & 0xff);
-        if (rsig)
+        if (rsig != NULL)
             *rsig = (unsigned char)(*psig & 0xff);
-        tls1_lookup_sigalg(phash, psign, psignhash, *psig);
+        lu = tls1_lookup_sigalg(*psig);
+        if (psign != NULL)
+            *psign = lu != NULL ? lu->sig : NID_undef;
+        if (phash != NULL)
+            *phash = lu != NULL ? lu->hash : NID_undef;
+        if (psignhash != NULL)
+            *psignhash = lu != NULL ? lu->sigandhash : NID_undef;
     }
     return (int)numsigalgs;
 }
@@ -1689,35 +1673,40 @@ int SSL_get_shared_sigalgs(SSL *s, int idx,
                            int *psign, int *phash, int *psignhash,
                            unsigned char *rsig, unsigned char *rhash)
 {
-    TLS_SIGALGS *shsigalgs = s->cert->shared_sigalgs;
-    if (!shsigalgs || idx >= (int)s->cert->shared_sigalgslen
-            || s->cert->shared_sigalgslen > INT_MAX)
+    const SIGALG_LOOKUP *shsigalgs;
+    if (s->cert->shared_sigalgs == NULL
+        || idx < 0
+        || idx >= (int)s->cert->shared_sigalgslen
+        || s->cert->shared_sigalgslen > INT_MAX)
         return 0;
-    shsigalgs += idx;
-    if (phash)
-        *phash = shsigalgs->hash_nid;
-    if (psign)
-        *psign = shsigalgs->sign_nid;
-    if (psignhash)
-        *psignhash = shsigalgs->signandhash_nid;
-    if (rsig)
-        *rsig = (unsigned char)(shsigalgs->rsigalg & 0xff);
-    if (rhash)
-        *rhash = (unsigned char)((shsigalgs->rsigalg >> 8) & 0xff);
+    shsigalgs = s->cert->shared_sigalgs[idx];
+    if (phash != NULL)
+        *phash = shsigalgs->hash;
+    if (psign != NULL)
+        *psign = shsigalgs->sig;
+    if (psignhash != NULL)
+        *psignhash = shsigalgs->sigandhash;
+    if (rsig != NULL)
+        *rsig = (unsigned char)(shsigalgs->sigalg & 0xff);
+    if (rhash != NULL)
+        *rhash = (unsigned char)((shsigalgs->sigalg >> 8) & 0xff);
     return (int)s->cert->shared_sigalgslen;
 }
 
-#define MAX_SIGALGLEN   (TLSEXT_hash_num * TLSEXT_signature_num * 2)
+/* Maximum possible number of unique entries in sigalgs array */
+#define TLS_MAX_SIGALGCNT (OSSL_NELEM(sigalg_lookup_tbl) * 2)
 
 typedef struct {
     size_t sigalgcnt;
-    int sigalgs[MAX_SIGALGLEN];
+    int sigalgs[TLS_MAX_SIGALGCNT];
 } sig_cb_st;
 
 static void get_sigorhash(int *psig, int *phash, const char *str)
 {
     if (strcmp(str, "RSA") == 0) {
         *psig = EVP_PKEY_RSA;
+    } else if (strcmp(str, "RSA-PSS") == 0 || strcmp(str, "PSS") == 0) {
+        *psig = EVP_PKEY_RSA_PSS;
     } else if (strcmp(str, "DSA") == 0) {
         *psig = EVP_PKEY_DSA;
     } else if (strcmp(str, "ECDSA") == 0) {
@@ -1728,31 +1717,44 @@ static void get_sigorhash(int *psig, int *phash, const char *str)
             *phash = OBJ_ln2nid(str);
     }
 }
+/* Maximum length of a signature algorithm string component */
+#define TLS_MAX_SIGSTRING_LEN   40
 
 static int sig_cb(const char *elem, int len, void *arg)
 {
     sig_cb_st *sarg = arg;
     size_t i;
-    char etmp[20], *p;
+    char etmp[TLS_MAX_SIGSTRING_LEN], *p;
     int sig_alg = NID_undef, hash_alg = NID_undef;
     if (elem == NULL)
         return 0;
-    if (sarg->sigalgcnt == MAX_SIGALGLEN)
+    if (sarg->sigalgcnt == TLS_MAX_SIGALGCNT)
         return 0;
     if (len > (int)(sizeof(etmp) - 1))
         return 0;
     memcpy(etmp, elem, len);
     etmp[len] = 0;
     p = strchr(etmp, '+');
-    if (!p)
-        return 0;
-    *p = 0;
-    p++;
-    if (!*p)
-        return 0;
-
-    get_sigorhash(&sig_alg, &hash_alg, etmp);
-    get_sigorhash(&sig_alg, &hash_alg, p);
+    /* See if we have a match for TLS 1.3 names */
+    if (p == NULL) {
+        const SIGALG_LOOKUP *s;
+
+        for (i = 0, s = sigalg_lookup_tbl; i < OSSL_NELEM(sigalg_lookup_tbl);
+             i++, s++) {
+            if (s->name != NULL && strcmp(etmp, s->name) == 0) {
+                sig_alg = s->sig;
+                hash_alg = s->hash;
+                break;
+            }
+        }
+    } else {
+        *p = 0;
+        p++;
+        if (*p == 0)
+            return 0;
+        get_sigorhash(&sig_alg, &hash_alg, etmp);
+        get_sigorhash(&sig_alg, &hash_alg, p);
+    }
 
     if (sig_alg == NID_undef || hash_alg == NID_undef)
         return 0;
@@ -1781,10 +1783,9 @@ int tls1_set_sigalgs_list(CERT *c, const char *str, int client)
     return tls1_set_sigalgs(c, sig.sigalgs, sig.sigalgcnt, client);
 }
 
-/* TODO(TLS1.3): Needs updating to allow setting of TLS1.3 sig algs */
 int tls1_set_sigalgs(CERT *c, const int *psig_nids, size_t salglen, int client)
 {
-    unsigned int *sigalgs, *sptr;
+    uint16_t *sigalgs, *sptr;
     size_t i;
 
     if (salglen & 1)
@@ -1792,10 +1793,6 @@ int tls1_set_sigalgs(CERT *c, const int *psig_nids, size_t salglen, int client)
     sigalgs = OPENSSL_malloc((salglen / 2) * sizeof(*sigalgs));
     if (sigalgs == NULL)
         return 0;
-    /*
-     * TODO(TLS1.3): Somehow we need to be able to set RSA-PSS as well as
-     * RSA-PKCS1. For now we only allow setting of RSA-PKCS1
-     */
     for (i = 0, sptr = sigalgs; i < salglen; i += 2) {
         size_t j;
         const SIGALG_LOOKUP *curr;
@@ -1804,9 +1801,6 @@ int tls1_set_sigalgs(CERT *c, const int *psig_nids, size_t salglen, int client)
 
         for (j = 0, curr = sigalg_lookup_tbl; j < OSSL_NELEM(sigalg_lookup_tbl);
              j++, curr++) {
-            /* Skip setting PSS so we get PKCS1 by default */
-            if (SIGID_IS_PSS(curr->sigalg))
-                continue;
             if (curr->hash == md_id && curr->sig == sig_id) {
                 *sptr++ = curr->sigalg;
                 break;
@@ -1844,7 +1838,7 @@ static int tls1_check_sig_alg(CERT *c, X509 *x, int default_nid)
     if (default_nid)
         return sig_nid == default_nid ? 1 : 0;
     for (i = 0; i < c->shared_sigalgslen; i++)
-        if (sig_nid == c->shared_sigalgs[i].signandhash_nid)
+        if (sig_nid == c->shared_sigalgs[i]->sigandhash)
             return 1;
     return 0;
 }
@@ -1942,8 +1936,7 @@ int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain,
         /* If no sigalgs extension use defaults from RFC5246 */
         else {
             switch (idx) {
-            case SSL_PKEY_RSA_ENC:
-            case SSL_PKEY_RSA_SIGN:
+            case SSL_PKEY_RSA:
                 rsign = EVP_PKEY_RSA;
                 default_nid = NID_sha1WithRSAEncryption;
                 break;
@@ -1984,10 +1977,11 @@ int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain,
          */
         if (default_nid > 0 && c->conf_sigalgs) {
             size_t j;
-            const unsigned int *p = c->conf_sigalgs;
+            const uint16_t *p = c->conf_sigalgs;
             for (j = 0; j < c->conf_sigalgslen; j++, p++) {
-                if (tls_sigalg_get_hash(*p) == NID_sha1
-                        && tls_sigalg_get_sig(*p) == rsign)
+                const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(*p);
+
+                if (lu != NULL && lu->hash == NID_sha1 && lu->sig == rsign)
                     break;
             }
             if (j == c->conf_sigalgslen) {
@@ -2129,8 +2123,7 @@ int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain,
 /* Set validity of certificates in an SSL structure */
 void tls1_set_cert_validity(SSL *s)
 {
-    tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_RSA_ENC);
-    tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_RSA_SIGN);
+    tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_RSA);
     tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_DSA_SIGN);
     tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_ECC);
     tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_GOST01);
@@ -2156,8 +2149,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) {
@@ -2267,3 +2261,173 @@ int ssl_security_cert_chain(SSL *s, STACK_OF(X509) *sk, X509 *x, int vfy)
     }
     return 1;
 }
+
+/*
+ * Choose an appropriate signature algorithm based on available certificates
+ * 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
+        int curve = -1;
+#endif
+
+        /* Look for a certificate matching shared sigaglgs */
+        for (i = 0; i < s->cert->shared_sigalgslen; i++) {
+            lu = s->cert->shared_sigalgs[i];
+
+            /* Skip RSA if not PSS */
+            if (lu->sig == EVP_PKEY_RSA)
+                continue;
+            if (ssl_md(lu->hash_idx) == NULL)
+                continue;
+            idx = lu->sig_idx;
+            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(s->cert->pkeys[idx].privatekey);
+
+                    curve = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
+                }
+                if (lu->curve != NID_undef && curve != lu->curve)
+                    continue;
+#else
+                continue;
+#endif
+            }
+            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 {
+        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 {
+            /* 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)) {
+            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) {
+                    if (al == NULL)
+                        return 1;
+                    *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) {
+                    if (al == NULL)
+                        return 1;
+                    *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) {
+                    if (al == NULL)
+                        return 1;
+                    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) {
+                if (al == NULL)
+                    return 1;
+                *al = SSL_AD_INTERNAL_ERROR;
+                SSLerr(SSL_F_TLS_CHOOSE_SIGALG, ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+        }
+    }
+    if (idx == -1) {
+        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];
+    s->cert->key = s->s3->tmp.cert;
+    s->s3->tmp.sigalg = lu;
+    return 1;
+}