don't use pseudo digests for default values of keys
[oweals/openssl.git] / ssl / t1_lib.c
index e120a87fc2bb78dc3a9f50833606e7baa16ac677..88f70d73bf6cdb1ae7781b514376189af1dd9006 100644 (file)
@@ -123,6 +123,8 @@ const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT;
 static int tls_decrypt_ticket(SSL *s, const unsigned char *tick, int ticklen,
                                const unsigned char *sess_id, int sesslen,
                                SSL_SESSION **psess);
+static int ssl_check_clienthello_tlsext(SSL *s);
+int ssl_check_serverhello_tlsext(SSL *s);
 #endif
 
 SSL3_ENC_METHOD TLSv1_enc_data={
@@ -627,19 +629,43 @@ static unsigned char tls12_sigalgs[] = {
 #endif
 };
 
-int tls12_get_req_sig_algs(SSL *s, unsigned char *p)
+size_t tls12_get_sig_algs(SSL *s, unsigned char *p)
        {
-       size_t slen = sizeof(tls12_sigalgs);
+       const unsigned char *sigs;
+       size_t sigslen;
+       sigs = s->cert->conf_sigalgs;
+
+       if (sigs)
+               sigslen = s->cert->conf_sigalgslen;
+       else
+               {
+               sigs = tls12_sigalgs;
+               sigslen = sizeof(tls12_sigalgs);
 #ifdef OPENSSL_FIPS
-       /* If FIPS mode don't include MD5 which is last */
-       if (FIPS_mode())
-               slen -= 2;
+               /* If FIPS mode don't include MD5 which is last */
+               if (FIPS_mode())
+                       sigslen -= 2;
 #endif
+               }
+
        if (p)
-               memcpy(p, tls12_sigalgs, slen);
-       return (int)slen;
+               memcpy(p, sigs, sigslen);
+       return sigslen;
        }
 
+/* byte_compare is a compare function for qsort(3) that compares bytes. */
+static int byte_compare(const void *in_a, const void *in_b)
+       {
+       unsigned char a = *((const unsigned char*) in_a);
+       unsigned char b = *((const unsigned char*) in_b);
+
+       if (a > b)
+               return 1;
+       else if (a < b)
+               return -1;
+       return 0;
+}
+
 unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
        {
        int extdatalen=0;
@@ -859,13 +885,15 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
 
        if (TLS1_get_client_version(s) >= TLS1_2_VERSION)
                {
-               if ((size_t)(limit - ret) < sizeof(tls12_sigalgs) + 6)
+               size_t salglen;
+               salglen = tls12_get_sig_algs(s, NULL);
+               if ((size_t)(limit - ret) < salglen + 6)
                        return NULL; 
                s2n(TLSEXT_TYPE_signature_algorithms,ret);
-               s2n(sizeof(tls12_sigalgs) + 2, ret);
-               s2n(sizeof(tls12_sigalgs), ret);
-               memcpy(ret, tls12_sigalgs, sizeof(tls12_sigalgs));
-               ret += sizeof(tls12_sigalgs);
+               s2n(salglen + 2, ret);
+               s2n(salglen, ret);
+               tls12_get_sig_algs(s, ret);
+               ret += salglen;
                }
 
 #ifdef TLSEXT_TYPE_opaque_prf_input
@@ -981,7 +1009,27 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                 ret += el;
                 }
 
-       if ((extdatalen = ret-p-2)== 0) 
+       /* Add TLS extension Server_Authz_DataFormats to the ClientHello */
+       /* 2 bytes for extension type */
+       /* 2 bytes for extension length */
+       /* 1 byte for the list length */
+       /* 1 byte for the list (we only support audit proofs) */
+       if (s->ctx->tlsext_authz_server_audit_proof_cb != NULL)
+               {
+               size_t lenmax;
+                const unsigned short ext_len = 2;
+                const unsigned char list_len = 1;
+
+               if ((lenmax = limit - ret - 6) < 0) return NULL;
+
+               s2n(TLSEXT_TYPE_server_authz, ret);
+                /* Extension length: 2 bytes */
+               s2n(ext_len, ret);
+               *(ret++) = list_len;
+               *(ret++) = TLSEXT_AUTHZDATAFORMAT_audit_proof;
+               }
+
+       if ((extdatalen = ret-p-2) == 0)
                return p;
 
        s2n(extdatalen,p);
@@ -1168,6 +1216,79 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
                }
 #endif
 
+       /* If the client supports authz then see whether we have any to offer
+        * to it. */
+       if (s->s3->tlsext_authz_client_types_len)
+               {
+               size_t authz_length;
+               /* By now we already know the new cipher, so we can look ahead
+                * to see whether the cert we are going to send
+                * has any authz data attached to it. */
+               const unsigned char* authz = ssl_get_authz_data(s, &authz_length);
+               const unsigned char* const orig_authz = authz;
+               size_t i;
+               unsigned authz_count = 0;
+
+               /* The authz data contains a number of the following structures:
+                *      uint8_t authz_type
+                *      uint16_t length
+                *      uint8_t data[length]
+                *
+                * First we walk over it to find the number of authz elements. */
+               for (i = 0; i < authz_length; i++)
+                       {
+                       unsigned short length;
+                       unsigned char type;
+
+                       type = *(authz++);
+                       if (memchr(s->s3->tlsext_authz_client_types,
+                                  type,
+                                  s->s3->tlsext_authz_client_types_len) != NULL)
+                               authz_count++;
+
+                       n2s(authz, length);
+                       /* n2s increments authz by 2 */
+                       i += 2;
+                       authz += length;
+                       i += length;
+                       }
+
+               if (authz_count)
+                       {
+                       /* Add TLS extension server_authz to the ServerHello message
+                        * 2 bytes for extension type
+                        * 2 bytes for extension length
+                        * 1 byte for the list length
+                        * n bytes for the list */
+                       const unsigned short ext_len = 1 + authz_count;
+
+                       if ((long)(limit - ret - 4 - ext_len) < 0) return NULL;
+                       s2n(TLSEXT_TYPE_server_authz, ret);
+                       s2n(ext_len, ret);
+                       *(ret++) = authz_count;
+                       s->s3->tlsext_authz_promised_to_client = 1;
+                       }
+
+               authz = orig_authz;
+               for (i = 0; i < authz_length; i++)
+                       {
+                       unsigned short length;
+                       unsigned char type;
+
+                       authz_count++;
+                       type = *(authz++);
+                       if (memchr(s->s3->tlsext_authz_client_types,
+                                  type,
+                                  s->s3->tlsext_authz_client_types_len) != NULL)
+                               *(ret++) = type;
+                       n2s(authz, length);
+                       /* n2s increments authz by 2 */
+                       i += 2;
+                       authz += length;
+                       i += length;
+                       }
+               }
+
        if ((extdatalen = ret-p-2)== 0) 
                return p;
 
@@ -1182,7 +1303,6 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
        unsigned short len;
        unsigned char *data = *p;
        int renegotiate_seen = 0;
-       int sigalg_seen = 0;
 
        s->servername_done = 0;
        s->tlsext_status_type = -1;
@@ -1194,6 +1314,18 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
        s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
                               SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
 #endif
+       /* Clear any signature algorithms extension received */
+       if (s->cert->peer_sigalgs)
+               {
+               OPENSSL_free(s->cert->peer_sigalgs);
+               s->cert->peer_sigalgs = NULL;
+               }
+       /* Clear any shared sigtnature algorithms */
+       if (s->cert->shared_sigalgs)
+               {
+               OPENSSL_free(s->cert->shared_sigalgs);
+               s->cert->shared_sigalgs = NULL;
+               }
 
        if (data >= (d+n-2))
                goto ri_check;
@@ -1469,15 +1601,14 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
                else if (type == TLSEXT_TYPE_signature_algorithms)
                        {
                        int dsize;
-                       if (sigalg_seen || size < 2) 
+                       if (s->cert->peer_sigalgs || size < 2) 
                                {
                                *al = SSL_AD_DECODE_ERROR;
                                return 0;
                                }
-                       sigalg_seen = 1;
                        n2s(data,dsize);
                        size -= 2;
-                       if (dsize != size || dsize & 1) 
+                       if (dsize != size || dsize & 1 || !dsize
                                {
                                *al = SSL_AD_DECODE_ERROR;
                                return 0;
@@ -1487,6 +1618,16 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
                                *al = SSL_AD_DECODE_ERROR;
                                return 0;
                                }
+                       /* If sigalgs received and no shared algorithms fatal
+                        * error.
+                        */
+                       if (s->cert->peer_sigalgs && !s->cert->shared_sigalgs)
+                               {
+                               SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT,
+                                       SSL_R_NO_SHARED_SIGATURE_ALGORITHMS);
+                               *al = SSL_AD_ILLEGAL_PARAMETER;
+                               return 0;
+                               }
                        }
                else if (type == TLSEXT_TYPE_status_request &&
                         s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb)
@@ -1619,7 +1760,7 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
 #endif
 #ifndef OPENSSL_NO_NEXTPROTONEG
                else if (type == TLSEXT_TYPE_next_proto_neg &&
-                         s->s3->tmp.finish_md_len == 0)
+                        s->s3->tmp.finish_md_len == 0)
                        {
                        /* We shouldn't accept this extension on a
                         * renegotiation.
@@ -1648,9 +1789,69 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
                                return 0;
                         }
 
+               else if (type == TLSEXT_TYPE_server_authz)
+                       {
+                       unsigned char *sdata = data;
+                       unsigned char server_authz_dataformatlist_length;
+
+                       if (size == 0)
+                               {
+                               *al = TLS1_AD_DECODE_ERROR;
+                               return 0;
+                               }
+
+                       server_authz_dataformatlist_length = *(sdata++);
+
+                       if (server_authz_dataformatlist_length != size - 1)
+                               {
+                               *al = TLS1_AD_DECODE_ERROR;
+                               return 0;
+                               }
+
+                       /* Successful session resumption uses the same authz
+                        * information as the original session so we ignore this
+                        * in the case of a session resumption. */
+                       if (!s->hit)
+                               {
+                               size_t i;
+                               if (s->s3->tlsext_authz_client_types != NULL)
+                                       OPENSSL_free(s->s3->tlsext_authz_client_types);
+                               s->s3->tlsext_authz_client_types =
+                                       OPENSSL_malloc(server_authz_dataformatlist_length);
+                               if (!s->s3->tlsext_authz_client_types)
+                                       {
+                                       *al = TLS1_AD_INTERNAL_ERROR;
+                                       return 0;
+                                       }
+
+                               s->s3->tlsext_authz_client_types_len =
+                                       server_authz_dataformatlist_length;
+                               memcpy(s->s3->tlsext_authz_client_types,
+                                      sdata,
+                                      server_authz_dataformatlist_length);
+
+                               /* Sort the types in order to check for duplicates. */
+                               qsort(s->s3->tlsext_authz_client_types,
+                                     server_authz_dataformatlist_length,
+                                     1 /* element size */,
+                                     byte_compare);
+
+                               for (i = 0; i < server_authz_dataformatlist_length; i++)
+                                       {
+                                       if (i > 0 &&
+                                           s->s3->tlsext_authz_client_types[i] ==
+                                             s->s3->tlsext_authz_client_types[i-1])
+                                               {
+                                               *al = TLS1_AD_DECODE_ERROR;
+                                               return 0;
+                                               }
+                                       }
+                               }
+                       }
+
                data+=size;
                }
-                               
+
        *p = data;
 
        ri_check:
@@ -1665,6 +1866,9 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
                                SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
                return 0;
                }
+       /* If no signature algorithms extension set default values */
+       if (!s->cert->peer_sigalgs)
+               ssl_cert_set_default_md(s->cert);
 
        return 1;
        }
@@ -1690,7 +1894,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
 /* ssl_next_proto_validate validates a Next Protocol Negotiation block. No
  * elements of zero length are allowed and the set of elements must exactly fill
  * the length of the block. */
-static int ssl_next_proto_validate(unsigned char *d, unsigned len)
+static char ssl_next_proto_validate(unsigned char *d, unsigned len)
        {
        unsigned int off = 0;
 
@@ -1706,7 +1910,7 @@ static int ssl_next_proto_validate(unsigned char *d, unsigned len)
        }
 #endif
 
-int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
+static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
        {
        unsigned short length;
        unsigned short type;
@@ -1914,7 +2118,46 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                                 return 0;
                         }
 
-               data+=size;             
+               else if (type == TLSEXT_TYPE_server_authz)
+                       {
+                       /* We only support audit proofs. It's an error to send
+                        * an authz hello extension if the client
+                        * didn't request a proof. */
+                       unsigned char *sdata = data;
+                       unsigned char server_authz_dataformatlist_length;
+
+                       if (!s->ctx->tlsext_authz_server_audit_proof_cb)
+                               {
+                               *al = TLS1_AD_UNSUPPORTED_EXTENSION;
+                               return 0;
+                               }
+
+                       if (!size)
+                               {
+                               *al = TLS1_AD_DECODE_ERROR;
+                               return 0;
+                               }
+
+                       server_authz_dataformatlist_length = *(sdata++);
+                       if (server_authz_dataformatlist_length != size - 1)
+                               {
+                               *al = TLS1_AD_DECODE_ERROR;
+                               return 0;
+                               }
+
+                       /* We only support audit proofs, so a legal ServerHello
+                        * authz list contains exactly one entry. */
+                       if (server_authz_dataformatlist_length != 1 ||
+                               sdata[0] != TLSEXT_AUTHZDATAFORMAT_audit_proof)
+                               {
+                               *al = TLS1_AD_UNSUPPORTED_EXTENSION;
+                               return 0;
+                               }
+
+                       s->s3->tlsext_authz_server_promised = 1;
+                       }
+               data += size;
                }
 
        if (data != d+n)
@@ -1960,7 +2203,7 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
                {
                *al = SSL_AD_HANDSHAKE_FAILURE;
-               SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT,
+               SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT,
                                SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
                return 0;
                }
@@ -2040,7 +2283,7 @@ int ssl_prepare_serverhello_tlsext(SSL *s)
        return 1;
        }
 
-int ssl_check_clienthello_tlsext(SSL *s)
+static int ssl_check_clienthello_tlsext(SSL *s)
        {
        int ret=SSL_TLSEXT_ERR_NOACK;
        int al = SSL_AD_UNRECOGNIZED_NAME;
@@ -2277,6 +2520,25 @@ int ssl_check_serverhello_tlsext(SSL *s)
                }
        }
 
+int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n) 
+       {
+       int al = -1;
+       if (s->version < SSL3_VERSION)
+               return 1;
+       if (ssl_scan_serverhello_tlsext(s, p, d, n, &al) <= 0) 
+               {
+               ssl3_send_alert(s,SSL3_AL_FATAL,al); 
+               return 0;
+               }
+
+       if (ssl_check_serverhello_tlsext(s) <= 0) 
+               {
+               SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT,SSL_R_SERVERHELLO_TLSEXT);
+               return 0;
+               }
+       return 1;
+}
+
 /* Since the server cache lookup is done early on in the processing of the
  * ClientHello, and other operations depend on the result, we need to handle
  * any TLS session ticket extension at the same time.
@@ -2613,11 +2875,145 @@ const EVP_MD *tls12_get_hash(unsigned char hash_alg)
                }
        }
 
+static int tls12_get_pkey_idx(unsigned char sig_alg)
+       {
+       switch(sig_alg)
+               {
+#ifndef OPENSSL_NO_RSA
+       case TLSEXT_signature_rsa:
+               return SSL_PKEY_RSA_SIGN;
+#endif
+#ifndef OPENSSL_NO_DSA
+       case TLSEXT_signature_dsa:
+               return SSL_PKEY_DSA_SIGN;
+#endif
+#ifndef OPENSSL_NO_ECDSA
+       case TLSEXT_signature_ecdsa:
+               return SSL_PKEY_ECC;
+#endif
+               }
+       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, const unsigned char *data)
+       {
+       int sign_nid, hash_nid;
+       if (!phash_nid && !psign_nid && !psignhash_nid)
+               return;
+       if (phash_nid || psignhash_nid)
+               {
+               hash_nid = tls12_find_nid(data[0], tls12_md,
+                                       sizeof(tls12_md)/sizeof(tls12_lookup));
+               if (phash_nid)
+                       *phash_nid = hash_nid;
+               }
+       if (psign_nid || psignhash_nid)
+               {
+               sign_nid = tls12_find_nid(data[1], tls12_sig,
+                                       sizeof(tls12_sig)/sizeof(tls12_lookup));
+               if (psign_nid)
+                       *psign_nid = sign_nid;
+               }
+       if (psignhash_nid)
+               {
+               if (sign_nid && hash_nid)
+                       OBJ_find_sigid_by_algs(psignhash_nid,
+                                                       hash_nid, sign_nid);
+               else
+                       *psignhash_nid = NID_undef;
+               }
+       }
+/* Given preference and allowed sigalgs set shared sigalgs */
+static int tls12_do_shared_sigalgs(TLS_SIGALGS *shsig,
+                               const unsigned char *pref, size_t preflen,
+                               const unsigned char *allow, size_t allowlen)
+       {
+       const unsigned char *ptmp, *atmp;
+       size_t i, j, nmatch = 0;
+       for (i = 0, ptmp = pref; i < preflen; i+=2, ptmp+=2)
+               {
+               /* Skip disabled hashes or signature algorithms */
+               if (tls12_get_hash(ptmp[0]) == NULL)
+                       continue;
+               if (tls12_get_pkey_idx(ptmp[1]) == -1)
+                       continue;
+               for (j = 0, atmp = allow; j < allowlen; j+=2, atmp+=2)
+                       {
+                       if (ptmp[0] == atmp[0] && ptmp[1] == atmp[1])
+                               {
+                               nmatch++;
+                               if (shsig)
+                                       {
+                                       shsig->rhash = ptmp[0];
+                                       shsig->rsign = ptmp[1];
+                                       tls1_lookup_sigalg(&shsig->hash_nid,
+                                               &shsig->sign_nid,
+                                               &shsig->signandhash_nid,
+                                               ptmp);
+                                       shsig++;
+                                       }
+                               break;
+                               }
+                       }
+               }
+       return nmatch;
+       }
+
+/* Set shared signature algorithms for SSL structures */
+static int tls1_set_shared_sigalgs(SSL *s)
+       {
+       const unsigned char *pref, *allow, *conf;
+       size_t preflen, allowlen, conflen;
+       size_t nmatch;
+       TLS_SIGALGS *salgs = NULL;
+       CERT *c = s->cert;
+       conf = c->conf_sigalgs;
+       if (conf)
+               conflen = c->conf_sigalgslen;
+       else
+               {
+               conf = tls12_sigalgs;
+               conflen = sizeof(tls12_sigalgs);
+#ifdef OPENSSL_FIPS
+               if (FIPS_mode())
+                       conflen -= 2;
+#endif
+               }
+       if(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE)
+               {
+               pref = conf;
+               preflen = conflen;
+               allow = c->peer_sigalgs;
+               allowlen = c->peer_sigalgslen;
+               }
+       else
+               {
+               allow = conf;
+               allowlen = conflen;
+               pref = c->peer_sigalgs;
+               preflen = c->peer_sigalgslen;
+               }
+       nmatch = tls12_do_shared_sigalgs(NULL, pref, preflen, allow, allowlen);
+       if (!nmatch)
+               return 1;
+       salgs = OPENSSL_malloc(nmatch * sizeof(TLS_SIGALGS));
+       if (!salgs)
+               return 0;
+       nmatch = tls12_do_shared_sigalgs(salgs, pref, preflen, allow, allowlen);
+       c->shared_sigalgs = salgs;
+       c->shared_sigalgslen = nmatch;
+       return 1;
+       }
+               
+
 /* Set preferred digest for each key type */
 
 int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
        {
-       int i, idx;
+       int idx;
+       size_t i;
        const EVP_MD *md;
        CERT *c = s->cert;
        TLS_SIGALGS *sigptr;
@@ -2633,66 +3029,33 @@ int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
        c->pkeys[SSL_PKEY_RSA_ENC].digest = NULL;
        c->pkeys[SSL_PKEY_ECC].digest = NULL;
 
-       if (c->sigalgs)
-               OPENSSL_free(c->sigalgs);
-       c->sigalgs = OPENSSL_malloc((dsize/2) * sizeof(TLS_SIGALGS));
-       if (!c->sigalgs)
+       c->peer_sigalgs = OPENSSL_malloc(dsize);
+       if (!c->peer_sigalgs)
                return 0;
-       c->sigalgslen = dsize/2;
+       c->peer_sigalgslen = dsize;
+       memcpy(c->peer_sigalgs, data, dsize);
 
-       for (i = 0, sigptr = c->sigalgs; i < dsize; i += 2, sigptr++)
-               {
-               sigptr->rhash = data[i];
-               sigptr->rsign = data[i + 1];
-               sigptr->hash_nid = tls12_find_nid(sigptr->rhash, tls12_md,
-                                       sizeof(tls12_md)/sizeof(tls12_lookup));
-               sigptr->sign_nid = tls12_find_nid(sigptr->rsign, tls12_sig,
-                                       sizeof(tls12_sig)/sizeof(tls12_lookup));
-               if (!OBJ_find_sigid_by_algs(&sigptr->signandhash_nid,
-                                               sigptr->hash_nid,
-                                               sigptr->sign_nid))
-                       sigptr->signandhash_nid = NID_undef;
-               switch(sigptr->rsign)
-                       {
-#ifndef OPENSSL_NO_RSA
-                       case TLSEXT_signature_rsa:
-                       idx = SSL_PKEY_RSA_SIGN;
-                       break;
-#endif
-#ifndef OPENSSL_NO_DSA
-                       case TLSEXT_signature_dsa:
-                       idx = SSL_PKEY_DSA_SIGN;
-                       break;
-#endif
-#ifndef OPENSSL_NO_ECDSA
-                       case TLSEXT_signature_ecdsa:
-                       idx = SSL_PKEY_ECC;
-                       break;
-#endif
-                       default:
-                       continue;
-                       }
+       tls1_set_shared_sigalgs(s);
 
-               if (c->pkeys[idx].digest == NULL)
+       for (i = 0, sigptr = c->shared_sigalgs;
+                       i < c->shared_sigalgslen; i++, sigptr++)
+               {
+               idx = tls12_get_pkey_idx(sigptr->rsign);
+               if (idx > 0 && c->pkeys[idx].digest == NULL)
                        {
                        md = tls12_get_hash(sigptr->rhash);
-                       if (md)
-                               {
-                               c->pkeys[idx].digest = md;
-                               if (idx == SSL_PKEY_RSA_SIGN)
-                                       c->pkeys[SSL_PKEY_RSA_ENC].digest = md;
-                               }
+                       c->pkeys[idx].digest = md;
+                       if (idx == SSL_PKEY_RSA_SIGN)
+                               c->pkeys[SSL_PKEY_RSA_ENC].digest = md;
                        }
 
                }
-
-
        /* Set any remaining keys to default values. NOTE: if alg is not
         * supported it stays as NULL.
         */
 #ifndef OPENSSL_NO_DSA
        if (!c->pkeys[SSL_PKEY_DSA_SIGN].digest)
-               c->pkeys[SSL_PKEY_DSA_SIGN].digest = EVP_dss1();
+               c->pkeys[SSL_PKEY_DSA_SIGN].digest = EVP_sha1();
 #endif
 #ifndef OPENSSL_NO_RSA
        if (!c->pkeys[SSL_PKEY_RSA_SIGN].digest)
@@ -2703,37 +3066,53 @@ int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
 #endif
 #ifndef OPENSSL_NO_ECDSA
        if (!c->pkeys[SSL_PKEY_ECC].digest)
-               c->pkeys[SSL_PKEY_ECC].digest = EVP_ecdsa();
+               c->pkeys[SSL_PKEY_ECC].digest = EVP_sha1();
 #endif
        return 1;
        }
 
-#endif
 
 int SSL_get_sigalgs(SSL *s, int idx,
-                       int *psign, int *phash, int *psignandhash,
+                       int *psign, int *phash, int *psignhash,
                        unsigned char *rsig, unsigned char *rhash)
        {
-       if (s->cert->sigalgs == NULL)
+       const unsigned char *psig = s->cert->peer_sigalgs;
+       if (psig == NULL)
                return 0;
        if (idx >= 0)
                {
-               TLS_SIGALGS *psig;
-               if (idx >= (int)s->cert->sigalgslen)
+               idx <<= 1;
+               if (idx >= (int)s->cert->peer_sigalgslen)
                        return 0;
-               psig = s->cert->sigalgs + idx;
-               if (psign)
-                       *psign = psig->sign_nid;
-               if (phash)
-                       *phash = psig->hash_nid;
-               if (psignandhash)
-                       *psignandhash = psig->signandhash_nid;
-               if (rsig)
-                       *rsig = psig->rsign;
+               psig += idx;
                if (rhash)
-                       *rhash = psig->rhash;
+                       *rhash = psig[0];
+               if (rsig)
+                       *rsig = psig[1];
+               tls1_lookup_sigalg(phash, psign, psignhash, psig);
                }
-       return s->cert->sigalgslen;
+       return s->cert->peer_sigalgslen / 2;
+       }
+
+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)
+               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 = shsigalgs->rsign;
+       if (rhash)
+               *rhash = shsigalgs->rhash;
+       return s->cert->shared_sigalgslen;
        }
        
 
@@ -2881,3 +3260,104 @@ tls1_heartbeat(SSL *s)
        return ret;
        }
 #endif
+
+#define MAX_SIGALGLEN  (TLSEXT_hash_num * TLSEXT_signature_num * 2)
+
+typedef struct
+       {
+       size_t sigalgcnt;
+       int sigalgs[MAX_SIGALGLEN];
+       } sig_cb_st;
+
+static int sig_cb(const char *elem, int len, void *arg)
+       {
+       sig_cb_st *sarg = arg;
+       size_t i;
+       char etmp[20], *p;
+       int sig_alg, hash_alg;
+       if (sarg->sigalgcnt == MAX_SIGALGLEN)
+               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;
+
+       if (!strcmp(etmp, "RSA"))
+               sig_alg = EVP_PKEY_RSA;
+       else if (!strcmp(etmp, "DSA"))
+               sig_alg = EVP_PKEY_DSA;
+       else if (!strcmp(etmp, "ECDSA"))
+               sig_alg = EVP_PKEY_EC;
+       else return 0;
+
+       hash_alg = OBJ_sn2nid(p);
+       if (hash_alg == NID_undef)
+               hash_alg = OBJ_ln2nid(p);
+       if (hash_alg == NID_undef)
+               return 0;
+
+       for (i = 0; i < sarg->sigalgcnt; i+=2)
+               {
+               if (sarg->sigalgs[i] == sig_alg
+                       && sarg->sigalgs[i + 1] == hash_alg)
+                       return 0;
+               }
+       sarg->sigalgs[sarg->sigalgcnt++] = hash_alg;
+       sarg->sigalgs[sarg->sigalgcnt++] = sig_alg;
+       return 1;
+       }
+
+/* Set suppored signature algorithms based on a colon separated list
+ * of the form sig+hash e.g. RSA+SHA512:DSA+SHA512 */
+int tls1_set_sigalgs_list(CERT *c, const char *str)
+       {
+       sig_cb_st sig;
+       sig.sigalgcnt = 0;
+       if (!CONF_parse_list(str, ':', 1, sig_cb, &sig))
+               return 0;
+       return tls1_set_sigalgs(c, sig.sigalgs, sig.sigalgcnt);
+       }
+
+int tls1_set_sigalgs(CERT *c, const int *psig_nids, size_t salglen)
+       {
+       unsigned char *sigalgs, *sptr;
+       int rhash, rsign;
+       size_t i;
+       if (salglen & 1)
+               return 0;
+       sigalgs = OPENSSL_malloc(salglen);
+       if (sigalgs == NULL)
+               return 0;
+       for (i = 0, sptr = sigalgs; i < salglen; i+=2)
+               {
+               rhash = tls12_find_id(*psig_nids++, tls12_md,
+                                       sizeof(tls12_md)/sizeof(tls12_lookup));
+               rsign = tls12_find_id(*psig_nids++, tls12_sig,
+                               sizeof(tls12_sig)/sizeof(tls12_lookup));
+
+               if (rhash == -1 || rsign == -1)
+                       goto err;
+               *sptr++ = rhash;
+               *sptr++ = rsign;
+               }
+
+       if (c->conf_sigalgs)
+               OPENSSL_free(c->conf_sigalgs);
+
+       c->conf_sigalgs = sigalgs;
+       c->conf_sigalgslen = salglen;
+       return 1;
+
+       err:
+       OPENSSL_free(sigalgs);
+       return 0;
+       }
+
+#endif