Continuing TLS v1.2 support: add support for server parsing of
authorDr. Stephen Henson <steve@openssl.org>
Fri, 6 May 2011 13:00:07 +0000 (13:00 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Fri, 6 May 2011 13:00:07 +0000 (13:00 +0000)
signature algorithms extension and correct signature format for
server key exchange.

All ciphersuites should now work on the server but no client support and
no client certificate support yet.

CHANGES
apps/s_server.c
ssl/d1_srvr.c
ssl/s3_srvr.c
ssl/ssl_cert.c
ssl/ssl_lib.c
ssl/ssl_locl.h
ssl/t1_lib.c
ssl/tls1.h

diff --git a/CHANGES b/CHANGES
index 5191ed6870a8fb77bb371295ce58c64bd62593f1..a955b3fd983f2f30794be6806e77feef834bb766 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,12 @@
 
  Changes between 1.0.1 and 1.1.0  [xx XXX xxxx]
 
+  *) Add server support for TLS v1.2 signature algorithms extension. Switch
+     to new signature format when needed using client digest preference.
+     All server ciphersuites should now work correctly in TLS v1.2. No client
+     support yet and no support for client certificates.
+     [Steve Henson]
+
   *) Initial TLS v1.2 support. Add new SHA256 digest to ssl code, switch
      to SHA256 for PRF when using TLS v1.2 and later. Add new SHA256 based
      ciphersuites. At present only RSA key exchange ciphersuites work with
index de481f7794a787a46ca3b096e09b65c8ebd71ea4..56362aa95cd93fd76b5c19ed708c851970cd534e 100644 (file)
@@ -1526,6 +1526,9 @@ bad:
        SSL_CTX_set_quiet_shutdown(ctx,1);
        if (bugs) SSL_CTX_set_options(ctx,SSL_OP_ALL);
        if (hack) SSL_CTX_set_options(ctx,SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG);
+       /* HACK while TLS v1.2 is disabled by default */
+       if (!(off & SSL_OP_NO_TLSv1_2))
+               SSL_CTX_clear_options(ctx, SSL_OP_NO_TLSv1_2);
        SSL_CTX_set_options(ctx,off);
        /* DTLS: partial reads end up discarding unread UDP bytes :-( 
         * Setting read ahead solves this problem.
index f6d72f5fa601048b17e48fa38e8973a9a44757ee..2d63199dd60a68fa8f525e6dbc31d81502892bdc 100644 (file)
@@ -1139,7 +1139,7 @@ int dtls1_send_server_key_exchange(SSL *s)
                if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
                        && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
                        {
-                       if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher))
+                       if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher, NULL))
                                == NULL)
                                {
                                al=SSL_AD_DECODE_ERROR;
index 871909eceddcf271cf380d293dbf71fdabbaea01..4eec497bef7a4070018075a8cdeb0011948f5ceb 100644 (file)
@@ -1530,6 +1530,7 @@ int ssl3_send_server_key_exchange(SSL *s)
        BN_CTX *bn_ctx = NULL; 
 #endif
        EVP_PKEY *pkey;
+       const EVP_MD *md = NULL;
        unsigned char *p,*d;
        int al,i;
        unsigned long type;
@@ -1810,7 +1811,7 @@ int ssl3_send_server_key_exchange(SSL *s)
                if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
                        && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
                        {
-                       if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher))
+                       if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher,&md))
                                == NULL)
                                {
                                al=SSL_AD_DECODE_ERROR;
@@ -1888,7 +1889,8 @@ int ssl3_send_server_key_exchange(SSL *s)
                        /* n is the length of the params, they start at &(d[4])
                         * and p points to the space at the end. */
 #ifndef OPENSSL_NO_RSA
-                       if (pkey->type == EVP_PKEY_RSA)
+                       if (pkey->type == EVP_PKEY_RSA
+                                       && s->version < TLS1_2_VERSION)
                                {
                                q=md_buf;
                                j=0;
@@ -1915,44 +1917,37 @@ int ssl3_send_server_key_exchange(SSL *s)
                                }
                        else
 #endif
-#if !defined(OPENSSL_NO_DSA)
-                               if (pkey->type == EVP_PKEY_DSA)
+                       if (md)
                                {
-                               /* lets do DSS */
-                               EVP_SignInit_ex(&md_ctx,EVP_dss1(), NULL);
-                               EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
-                               EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
-                               EVP_SignUpdate(&md_ctx,&(d[4]),n);
-                               if (!EVP_SignFinal(&md_ctx,&(p[2]),
-                                       (unsigned int *)&i,pkey))
+                               /* For TLS1.2 and later send signature
+                                * algorithm */
+                               if (s->version >= TLS1_2_VERSION)
                                        {
-                                       SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_DSA);
-                                       goto err;
+                                       if (!tls12_get_sigandhash(p, pkey, md))
+                                               {
+                                               /* Should never happen */
+                                               al=SSL_AD_INTERNAL_ERROR;
+                                               SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+                                               goto f_err;
+                                               }
+                                       p+=2;
                                        }
-                               s2n(i,p);
-                               n+=i+2;
-                               }
-                       else
-#endif
-#if !defined(OPENSSL_NO_ECDSA)
-                               if (pkey->type == EVP_PKEY_EC)
-                               {
-                               /* let's do ECDSA */
-                               EVP_SignInit_ex(&md_ctx,EVP_ecdsa(), NULL);
+                               EVP_SignInit_ex(&md_ctx, md, NULL);
                                EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
                                EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
                                EVP_SignUpdate(&md_ctx,&(d[4]),n);
                                if (!EVP_SignFinal(&md_ctx,&(p[2]),
                                        (unsigned int *)&i,pkey))
                                        {
-                                       SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_ECDSA);
+                                       SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_EVP);
                                        goto err;
                                        }
                                s2n(i,p);
                                n+=i+2;
+                               if (s->version >= TLS1_2_VERSION)
+                                       n+= 2;
                                }
                        else
-#endif
                                {
                                /* Is this error check actually needed? */
                                al=SSL_AD_HANDSHAKE_FAILURE;
index 27256eea8145455f5e0ec89bc23c78e8736c49b7..917be318760f509aa90dbdaaabc5949b2735b7d5 100644 (file)
@@ -160,6 +160,21 @@ int SSL_get_ex_data_X509_STORE_CTX_idx(void)
        return ssl_x509_store_ctx_idx;
        }
 
+static void ssl_cert_set_default_md(CERT *cert)
+       {
+       /* Set digest values to defaults */
+#ifndef OPENSSL_NO_DSA
+       cert->pkeys[SSL_PKEY_DSA_SIGN].digest = EVP_dss1();
+#endif
+#ifndef OPENSSL_NO_RSA
+       cert->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1();
+       cert->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1();
+#endif
+#ifndef OPENSSL_NO_ECDSA
+       cert->pkeys[SSL_PKEY_ECC].digest = EVP_ecdsa();
+#endif
+       }
+
 CERT *ssl_cert_new(void)
        {
        CERT *ret;
@@ -174,7 +189,7 @@ CERT *ssl_cert_new(void)
 
        ret->key= &(ret->pkeys[SSL_PKEY_RSA_ENC]);
        ret->references=1;
-
+       ssl_cert_set_default_md(ret);
        return(ret);
        }
 
@@ -307,6 +322,10 @@ CERT *ssl_cert_dup(CERT *cert)
         * chain is held inside SSL_CTX */
 
        ret->references=1;
+       /* Set digests to defaults. NB: we don't copy existing values as they
+        * will be set during handshake.
+        */
+       ssl_cert_set_default_md(ret);
 
        return(ret);
        
index e191cce62401d6a2ffcafa05dd6f51a9cd04766c..114ad476a8b3ef2544a146c796d2303c919f831f 100644 (file)
@@ -2322,34 +2322,36 @@ X509 *ssl_get_server_send_cert(SSL *s)
        return(c->pkeys[i].x509);
        }
 
-EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *cipher)
+EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *cipher, const EVP_MD **pmd)
        {
        unsigned long alg_a;
        CERT *c;
+       int idx = -1;
 
        alg_a = cipher->algorithm_auth;
        c=s->cert;
 
        if ((alg_a & SSL_aDSS) &&
                (c->pkeys[SSL_PKEY_DSA_SIGN].privatekey != NULL))
-               return(c->pkeys[SSL_PKEY_DSA_SIGN].privatekey);
+               idx = SSL_PKEY_DSA_SIGN;
        else if (alg_a & SSL_aRSA)
                {
                if (c->pkeys[SSL_PKEY_RSA_SIGN].privatekey != NULL)
-                       return(c->pkeys[SSL_PKEY_RSA_SIGN].privatekey);
+                       idx = SSL_PKEY_RSA_SIGN;
                else if (c->pkeys[SSL_PKEY_RSA_ENC].privatekey != NULL)
-                       return(c->pkeys[SSL_PKEY_RSA_ENC].privatekey);
-               else
-                       return(NULL);
+                       idx = SSL_PKEY_RSA_ENC;
                }
        else if ((alg_a & SSL_aECDSA) &&
                 (c->pkeys[SSL_PKEY_ECC].privatekey != NULL))
-               return(c->pkeys[SSL_PKEY_ECC].privatekey);
-       else /* if (alg_a & SSL_aNULL) */
+               idx = SSL_PKEY_ECC;
+       if (idx == -1)
                {
                SSLerr(SSL_F_SSL_GET_SIGN_PKEY,ERR_R_INTERNAL_ERROR);
                return(NULL);
                }
+       if (pmd)
+               *pmd = c->pkeys[idx].digest;
+       return c->pkeys[idx].privatekey;
        }
 
 void ssl_update_cache(SSL *s,int mode)
index 3c025479870da14456c49c360464fde438d44047..3225d6517ac0e383d896f26befd6276b91afdf97 100644 (file)
@@ -461,6 +461,8 @@ typedef struct cert_pkey_st
        {
        X509 *x509;
        EVP_PKEY *privatekey;
+       /* Digest to use when signing */
+       const EVP_MD *digest;
        } CERT_PKEY;
 
 typedef struct cert_st
@@ -814,7 +816,7 @@ int ssl_undefined_function(SSL *s);
 int ssl_undefined_void_function(void);
 int ssl_undefined_const_function(const SSL *s);
 X509 *ssl_get_server_send_cert(SSL *);
-EVP_PKEY *ssl_get_sign_pkey(SSL *,const SSL_CIPHER *);
+EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *c, const EVP_MD **pmd);
 int ssl_cert_type(X509 *x,EVP_PKEY *pkey);
 void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher);
 STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *s);
@@ -1088,3 +1090,4 @@ int ssl_parse_clienthello_renegotiate_ext(SSL *s, unsigned char *d, int len,
                                          int *al);
 long ssl_get_algorithm2(SSL *s);
 #endif
+int tls12_get_sigandhash(unsigned char *p, EVP_PKEY *pk, const EVP_MD *md);
index a732200c519353d9c1775105fc2ae8cf431547fe..67a3f86adcc6528a0ae3d3191d25df3dab92646a 100644 (file)
@@ -122,6 +122,7 @@ 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 tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize);
 #endif
 
 SSL3_ENC_METHOD TLSv1_enc_data={
@@ -693,6 +694,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
        unsigned short len;
        unsigned char *data = *p;
        int renegotiate_seen = 0;
+       int sigalg_seen = 0;
 
        s->servername_done = 0;
        s->tlsext_status_type = -1;
@@ -956,6 +958,28 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                                return 0;
                        renegotiate_seen = 1;
                        }
+               else if (type == TLSEXT_TYPE_signature_algorithms)
+                       {
+                       int dsize;
+                       if (sigalg_seen || size < 2) 
+                               {
+                               *al = SSL_AD_DECODE_ERROR;
+                               return 0;
+                               }
+                       sigalg_seen = 1;
+                       n2s(data,dsize);
+                       size -= 2;
+                       if (dsize != size || dsize & 1) 
+                               {
+                               *al = SSL_AD_DECODE_ERROR;
+                               return 0;
+                               }
+                       if (!tls1_process_sigalgs(s, data, dsize))
+                               {
+                               *al = SSL_AD_DECODE_ERROR;
+                               return 0;
+                               }
+                       }
                else if (type == TLSEXT_TYPE_status_request &&
                         s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb)
                        {
@@ -1893,4 +1917,185 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
        return 0;
        }
 
+/* Tables to translate from NIDs to TLS v1.2 ids */
+
+typedef struct 
+       {
+       int nid;
+       int id;
+       } tls12_lookup;
+
+static tls12_lookup tls12_md[] = {
+#ifndef OPENSSL_NO_MD5
+       {NID_md5, TLSEXT_hash_md5},
+#endif
+#ifndef OPENSSL_NO_SHA
+       {NID_sha1, TLSEXT_hash_sha1},
+#endif
+#ifndef OPENSSL_NO_SHA256
+       {NID_sha224, TLSEXT_hash_sha224},
+       {NID_sha256, TLSEXT_hash_sha256},
+#endif
+#ifndef OPENSSL_NO_SHA512
+       {NID_sha384, TLSEXT_hash_sha384},
+       {NID_sha512, TLSEXT_hash_sha512}
+#endif
+};
+
+static tls12_lookup tls12_sig[] = {
+#ifndef OPENSSL_NO_RSA
+       {EVP_PKEY_RSA, TLSEXT_signature_rsa},
+#endif
+#ifndef OPENSSL_NO_RSA
+       {EVP_PKEY_DSA, TLSEXT_signature_dsa},
+#endif
+#ifndef OPENSSL_NO_ECDSA
+       {EVP_PKEY_EC, TLSEXT_signature_ecdsa}
+#endif
+};
+
+static int tls12_find_id(int nid, tls12_lookup *table, size_t tlen)
+       {
+       size_t i;
+       for (i = 0; i < tlen; i++)
+               {
+               if (table[i].nid == nid)
+                       return table[i].id;
+               }
+       return -1;
+       }
+#if 0
+static int tls12_find_nid(int id, tls12_lookup *table, size_t tlen)
+       {
+       size_t i;
+       for (i = 0; i < tlen; i++)
+               {
+               if (table[i].id == id)
+                       return table[i].nid;
+               }
+       return -1;
+       }
+#endif
+int tls12_get_sigandhash(unsigned char *p, EVP_PKEY *pk, const EVP_MD *md)
+       {
+       int sig_id, md_id;
+       md_id = tls12_find_id(EVP_MD_type(md), tls12_md,
+                               sizeof(tls12_md)/sizeof(tls12_lookup));
+       if (md_id == -1)
+               return 0;
+       sig_id = tls12_find_id(pk->type, tls12_sig,
+                               sizeof(tls12_sig)/sizeof(tls12_lookup));
+       if (sig_id == -1)
+               return 0;
+       p[0] = (unsigned char)md_id;
+       p[1] = (unsigned char)sig_id;
+       return 1;
+       }
+
+/* Set preferred digest for each key type */
+
+int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
+       {
+       int i, idx;
+       const EVP_MD *md;
+       CERT *c = s->cert;
+       /* Extension ignored for TLS versions below 1.2 */
+       if (s->version < TLS1_2_VERSION)
+               return 1;
+
+       c->pkeys[SSL_PKEY_DSA_SIGN].digest = NULL;
+       c->pkeys[SSL_PKEY_RSA_SIGN].digest = NULL;
+       c->pkeys[SSL_PKEY_RSA_ENC].digest = NULL;
+       c->pkeys[SSL_PKEY_ECC].digest = NULL;
+
+       for (i = 0; i < dsize; i += 2)
+               {
+               unsigned char hash_alg = data[i], sig_alg = data[i+1];
+
+               switch(sig_alg)
+                       {
+#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;
+                       }
+
+               if (c->pkeys[idx].digest)
+                       continue;
+
+               switch(hash_alg)
+                       {
+#ifndef OPENSSL_NO_MD5
+                       case TLSEXT_hash_md5:
+                       md = EVP_md5();
+                       break;
+#endif
+#ifndef OPENSSL_NO_SHA
+                       case TLSEXT_hash_sha1:
+                       md = EVP_sha1();
+                       break;
+#endif
+#ifndef OPENSSL_NO_SHA256
+                       case TLSEXT_hash_sha224:
+                       md = EVP_sha224();
+                       break;
+
+                       case TLSEXT_hash_sha256:
+                       md = EVP_sha256();
+                       break;
+#endif
+#ifndef OPENSSL_NO_SHA512
+                       case TLSEXT_hash_sha384:
+                       md = EVP_sha384();
+                       break;
+
+                       case TLSEXT_hash_sha512:
+                       md = EVP_sha512();
+                       break;
+#endif
+                       default:
+                       continue;
+
+                       }
+
+               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();
+#endif
+#ifndef OPENSSL_NO_RSA
+       if (!c->pkeys[SSL_PKEY_RSA_SIGN].digest)
+               {
+               c->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1();
+               c->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1();
+               }
+#endif
+#ifndef OPENSSL_NO_ECDSA
+       if (!c->pkeys[SSL_PKEY_ECC].digest)
+               c->pkeys[SSL_PKEY_ECC].digest = EVP_ecdsa();
+#endif
+       return 1;
+       }
+
 #endif
index 35937013056a04cd2d6961e0cffe5677c828079f..35efebee5954c57296f6a206e0764323d941d82f 100644 (file)
@@ -234,6 +234,21 @@ extern "C" {
 #define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2 2
 #define TLSEXT_ECPOINTFORMAT_last                      2
 
+/* Signature and hash algorithms from RFC 5246 */
+
+#define TLSEXT_signature_anonymous                     0
+#define TLSEXT_signature_rsa                           1
+#define TLSEXT_signature_dsa                           2
+#define TLSEXT_signature_ecdsa                         3
+
+#define TLSEXT_hash_none                               0
+#define TLSEXT_hash_md5                                        1
+#define TLSEXT_hash_sha1                               2
+#define TLSEXT_hash_sha224                             3
+#define TLSEXT_hash_sha256                             4
+#define TLSEXT_hash_sha384                             5
+#define TLSEXT_hash_sha512                             6
+
 #ifndef OPENSSL_NO_TLSEXT
 
 #define TLSEXT_MAXLEN_host_name 255