don't use pseudo digests for default values of keys
[oweals/openssl.git] / ssl / t1_lib.c
index dcfecf4f5b79b077215bfd268d286bc5fc210c7f..88f70d73bf6cdb1ae7781b514376189af1dd9006 100644 (file)
@@ -631,35 +631,26 @@ static unsigned char tls12_sigalgs[] = {
 
 size_t tls12_get_sig_algs(SSL *s, unsigned char *p)
        {
-       TLS_SIGALGS *sptr = s->cert->conf_sigalgs;
-       size_t slen;
+       const unsigned char *sigs;
+       size_t sigslen;
+       sigs = s->cert->conf_sigalgs;
 
-       /* Use custom signature algorithms if any are set */
-
-       if (sptr)
+       if (sigs)
+               sigslen = s->cert->conf_sigalgslen;
+       else
                {
-               slen = s->cert->conf_sigalgslen;
-               if (p)
-                       {
-                       size_t i;
-                       for (i = 0; i < slen; i++, sptr++)
-                               {
-                               *p++ = sptr->rhash;
-                               *p++ = sptr->rsign;
-                               }
-                       }
-               return slen * 2;
-               }
-               
-       slen = sizeof(tls12_sigalgs);
+               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 slen;
+               memcpy(p, sigs, sigslen);
+       return sigslen;
        }
 
 /* byte_compare is a compare function for qsort(3) that compares bytes. */
@@ -1312,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;
@@ -1324,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;
@@ -1599,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;
@@ -1617,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)
@@ -1855,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;
        }
@@ -2861,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;
@@ -2881,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->peer_sigalgs)
-               OPENSSL_free(c->peer_sigalgs);
-       c->peer_sigalgs = OPENSSL_malloc((dsize/2) * sizeof(TLS_SIGALGS));
+       c->peer_sigalgs = OPENSSL_malloc(dsize);
        if (!c->peer_sigalgs)
                return 0;
-       c->peer_sigalgslen = dsize/2;
+       c->peer_sigalgslen = dsize;
+       memcpy(c->peer_sigalgs, data, dsize);
 
-       for (i = 0, sigptr = c->peer_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)
@@ -2951,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->peer_sigalgs == NULL)
+       const unsigned char *psig = s->cert->peer_sigalgs;
+       if (psig == NULL)
                return 0;
        if (idx >= 0)
                {
-               TLS_SIGALGS *psig;
+               idx <<= 1;
                if (idx >= (int)s->cert->peer_sigalgslen)
                        return 0;
-               psig = s->cert->peer_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->peer_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;
        }
        
 
@@ -3130,7 +3261,7 @@ tls1_heartbeat(SSL *s)
        }
 #endif
 
-#define MAX_SIGALGLEN  (TLSEXT_hash_num * TLSEXT_signature_num *2)
+#define MAX_SIGALGLEN  (TLSEXT_hash_num * TLSEXT_signature_num * 2)
 
 typedef struct
        {
@@ -3194,35 +3325,27 @@ int tls1_set_sigalgs_list(CERT *c, const char *str)
        return tls1_set_sigalgs(c, sig.sigalgs, sig.sigalgcnt);
        }
 
-int tls1_set_sigalgs(CERT *c, const int *salg, size_t salglen)
+int tls1_set_sigalgs(CERT *c, const int *psig_nids, size_t salglen)
        {
-       TLS_SIGALGS *sigalgs, *sptr;
+       unsigned char *sigalgs, *sptr;
        int rhash, rsign;
        size_t i;
        if (salglen & 1)
                return 0;
-       salglen /= 2;
-       sigalgs = OPENSSL_malloc(sizeof(TLS_SIGALGS) * salglen);
+       sigalgs = OPENSSL_malloc(salglen);
        if (sigalgs == NULL)
                return 0;
-       for (i = 0, sptr = sigalgs; i < salglen; i++, sptr++)
+       for (i = 0, sptr = sigalgs; i < salglen; i+=2)
                {
-               sptr->hash_nid = *salg++;
-               sptr->sign_nid = *salg++;
-               rhash = tls12_find_id(sptr->hash_nid, tls12_md,
+               rhash = tls12_find_id(*psig_nids++, tls12_md,
                                        sizeof(tls12_md)/sizeof(tls12_lookup));
-               rsign = tls12_find_id(sptr->sign_nid, tls12_sig,
+               rsign = tls12_find_id(*psig_nids++, tls12_sig,
                                sizeof(tls12_sig)/sizeof(tls12_lookup));
 
                if (rhash == -1 || rsign == -1)
                        goto err;
-
-               if (!OBJ_find_sigid_by_algs(&sptr->signandhash_nid,
-                                               sptr->hash_nid,
-                                               sptr->sign_nid))
-                       sptr->signandhash_nid = NID_undef;
-               sptr->rhash = rhash;
-               sptr->rsign = rsign;
+               *sptr++ = rhash;
+               *sptr++ = rsign;
                }
 
        if (c->conf_sigalgs)
@@ -3236,3 +3359,5 @@ int tls1_set_sigalgs(CERT *c, const int *salg, size_t salglen)
        OPENSSL_free(sigalgs);
        return 0;
        }
+
+#endif