Initial TLS v1.2 client support. Include a default supported signature
authorDr. Stephen Henson <steve@openssl.org>
Mon, 9 May 2011 15:44:01 +0000 (15:44 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Mon, 9 May 2011 15:44:01 +0000 (15:44 +0000)
algorithms extension (including everything we support). Swicth to new
signature format where needed and relax ECC restrictions.

Not TLS v1.2 client certifcate support yet but client will handle case
where a certificate is requested and we don't have one.

CHANGES
apps/s_client.c
ssl/s3_clnt.c
ssl/s3_srvr.c
ssl/ssl.h
ssl/ssl_err.c
ssl/ssl_lib.c
ssl/ssl_locl.h
ssl/t1_enc.c
ssl/t1_lib.c

diff --git a/CHANGES b/CHANGES
index a955b3f..1ee3a47 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,12 @@
 
  Changes between 1.0.1 and 1.1.0  [xx XXX xxxx]
 
+  *) Initial TLS v1.2 client support. Add a default signature algorithms
+     extension including all the algorithms we support. Parse new signature
+     format in client key exchange. Relax some ECC signing restrictions for
+     TLS v1.2 as indicated in RFC5246.
+     [Steve Henson]
+
   *) 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
index faf7f39..2b8b145 100644 (file)
@@ -1103,6 +1103,9 @@ bad:
                SSL_CTX_set_psk_client_callback(ctx, psk_client_cb);
                }
 #endif
+       /* 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);
        if (bugs)
                SSL_CTX_set_options(ctx,SSL_OP_ALL|off);
        else
@@ -2011,6 +2014,18 @@ static void print_stuff(BIO *bio, SSL *s, int full)
        }
 #endif
 
+#ifdef SSL_DEBUG
+       {
+       /* Print out local port of connection: useful for debugging */
+       int sock;
+       struct sockaddr_in ladd;
+       socklen_t ladd_size = sizeof(ladd);
+       sock = SSL_get_fd(s);
+       getsockname(sock, (struct sockaddr *)&ladd, &ladd_size);
+       BIO_printf(bio_c_out, "LOCAL PORT is %u\n", ntohs(ladd.sin_port));
+       }
+#endif
+
        SSL_SESSION_print(bio,SSL_get_session(s));
        BIO_printf(bio,"---\n");
        if (peer != NULL)
index f96ec4f..0541de9 100644 (file)
@@ -1203,6 +1203,7 @@ int ssl3_get_key_exchange(SSL *s)
        int al,i,j,param_len,ok;
        long n,alg_k,alg_a;
        EVP_PKEY *pkey=NULL;
+       const EVP_MD *md = NULL;
 #ifndef OPENSSL_NO_RSA
        RSA *rsa=NULL;
 #endif
@@ -1653,6 +1654,38 @@ int ssl3_get_key_exchange(SSL *s)
        /* if it was signed, check the signature */
        if (pkey != NULL)
                {
+               if (s->version >= TLS1_2_VERSION)
+                       {
+                       int sigalg = tls12_get_sigid(pkey);
+                       /* Should never happen */
+                       if (sigalg == -1)
+                               {
+                               SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+                               goto err;
+                               }
+                       /* Check key type is consistent with signature */
+                       if (sigalg != (int)p[1])
+                               {
+                               SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_WRONG_SIGNATURE_TYPE);
+                               al=SSL_AD_DECODE_ERROR;
+                               goto f_err;
+                               }
+                       md = tls12_get_hash(p[0]);
+                       if (md == NULL)
+                               {
+                               SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNKNOWN_DIGEST);
+                               al=SSL_AD_DECODE_ERROR;
+                               goto f_err;
+                               }
+#ifdef SSL_DEBUG
+fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
+#endif
+                       p += 2;
+                       n -= 2;
+                       }
+               else
+                       md = EVP_sha1();
+                       
                n2s(p,i);
                n-=2;
                j=EVP_PKEY_size(pkey);
@@ -1666,7 +1699,7 @@ int ssl3_get_key_exchange(SSL *s)
                        }
 
 #ifndef OPENSSL_NO_RSA
-               if (pkey->type == EVP_PKEY_RSA)
+               if (pkey->type == EVP_PKEY_RSA && s->version < TLS1_2_VERSION)
                        {
                        int num;
 
@@ -1701,29 +1734,8 @@ int ssl3_get_key_exchange(SSL *s)
                        }
                else
 #endif
-#ifndef OPENSSL_NO_DSA
-                       if (pkey->type == EVP_PKEY_DSA)
-                       {
-                       /* lets do DSS */
-                       EVP_VerifyInit_ex(&md_ctx,EVP_dss1(), NULL);
-                       EVP_VerifyUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
-                       EVP_VerifyUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
-                       EVP_VerifyUpdate(&md_ctx,param,param_len);
-                       if (EVP_VerifyFinal(&md_ctx,p,(int)n,pkey) <= 0)
-                               {
-                               /* bad signature */
-                               al=SSL_AD_DECRYPT_ERROR;
-                               SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SIGNATURE);
-                               goto f_err;
-                               }
-                       }
-               else
-#endif
-#ifndef OPENSSL_NO_ECDSA
-                       if (pkey->type == EVP_PKEY_EC)
                        {
-                       /* let's do ECDSA */
-                       EVP_VerifyInit_ex(&md_ctx,EVP_ecdsa(), NULL);
+                       EVP_VerifyInit_ex(&md_ctx, md, NULL);
                        EVP_VerifyUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
                        EVP_VerifyUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
                        EVP_VerifyUpdate(&md_ctx,param,param_len);
@@ -1735,12 +1747,6 @@ int ssl3_get_key_exchange(SSL *s)
                                goto f_err;
                                }
                        }
-               else
-#endif
-                       {
-                       SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
-                       goto err;
-                       }
                }
        else
                {
@@ -1787,7 +1793,7 @@ int ssl3_get_certificate_request(SSL *s)
        {
        int ok,ret=0;
        unsigned long n,nc,l;
-       unsigned int llen,ctype_num,i;
+       unsigned int llen,sigalglen, ctype_num,i;
        X509_NAME *xn=NULL;
        const unsigned char *p,*q;
        unsigned char *d;
@@ -1843,6 +1849,17 @@ int ssl3_get_certificate_request(SSL *s)
        for (i=0; i<ctype_num; i++)
                s->s3->tmp.ctype[i]= p[i];
        p+=ctype_num;
+       /* HACK! For now just skip over signatature algorithms */
+       if (s->version >= TLS1_2_VERSION)
+               {
+               n2s(p, sigalglen);
+               p += sigalglen;
+               sigalglen += 2;
+               }
+       else
+               sigalglen = 0;
+               
+               
 
        /* get the CA RDNs */
        n2s(p,llen);
@@ -1855,7 +1872,7 @@ fclose(out);
 }
 #endif
 
-       if ((llen+ctype_num+2+1) != n)
+       if ((llen+ctype_num+sigalglen+2+1) != n)
                {
                ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
                SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_LENGTH_MISMATCH);
@@ -3059,7 +3076,7 @@ int ssl3_check_cert_and_algorithm(SSL *s)
        if (idx == SSL_PKEY_ECC)
                {
                if (ssl_check_srvr_ecc_cert_and_alg(sc->peer_pkeys[idx].x509,
-                   s->s3->tmp.new_cipher) == 0) 
+                                                               s) == 0) 
                        { /* check failed */
                        SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_BAD_ECC_CERT);
                        goto f_err;
index 4eec497..0f203ec 100644 (file)
@@ -1932,6 +1932,10 @@ int ssl3_send_server_key_exchange(SSL *s)
                                                }
                                        p+=2;
                                        }
+#ifdef SSL_DEBUG
+                               fprintf(stderr, "Using hash %s\n",
+                                                       EVP_MD_name(md));
+#endif
                                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);
index c487407..755dd85 100644 (file)
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -2500,6 +2500,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_R_UNKNOWN_CERTIFICATE_TYPE                  247
 #define SSL_R_UNKNOWN_CIPHER_RETURNED                   248
 #define SSL_R_UNKNOWN_CIPHER_TYPE                       249
+#define SSL_R_UNKNOWN_DIGEST                            357
 #define SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE                         250
 #define SSL_R_UNKNOWN_PKEY_TYPE                                 251
 #define SSL_R_UNKNOWN_PROTOCOL                          252
@@ -2520,6 +2521,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_R_WRONG_NUMBER_OF_KEY_BITS                  263
 #define SSL_R_WRONG_SIGNATURE_LENGTH                    264
 #define SSL_R_WRONG_SIGNATURE_SIZE                      265
+#define SSL_R_WRONG_SIGNATURE_TYPE                      358
 #define SSL_R_WRONG_SSL_VERSION                                 266
 #define SSL_R_WRONG_VERSION_NUMBER                      267
 #define SSL_R_X509_LIB                                  268
index af52856..76c8e1e 100644 (file)
@@ -543,6 +543,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {ERR_REASON(SSL_R_UNKNOWN_CERTIFICATE_TYPE),"unknown certificate type"},
 {ERR_REASON(SSL_R_UNKNOWN_CIPHER_RETURNED),"unknown cipher returned"},
 {ERR_REASON(SSL_R_UNKNOWN_CIPHER_TYPE)   ,"unknown cipher type"},
+{ERR_REASON(SSL_R_UNKNOWN_DIGEST)        ,"unknown digest"},
 {ERR_REASON(SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE),"unknown key exchange type"},
 {ERR_REASON(SSL_R_UNKNOWN_PKEY_TYPE)     ,"unknown pkey type"},
 {ERR_REASON(SSL_R_UNKNOWN_PROTOCOL)      ,"unknown protocol"},
@@ -563,6 +564,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {ERR_REASON(SSL_R_WRONG_NUMBER_OF_KEY_BITS),"wrong number of key bits"},
 {ERR_REASON(SSL_R_WRONG_SIGNATURE_LENGTH),"wrong signature length"},
 {ERR_REASON(SSL_R_WRONG_SIGNATURE_SIZE)  ,"wrong signature size"},
+{ERR_REASON(SSL_R_WRONG_SIGNATURE_TYPE)  ,"wrong signature type"},
 {ERR_REASON(SSL_R_WRONG_SSL_VERSION)     ,"wrong ssl version"},
 {ERR_REASON(SSL_R_WRONG_VERSION_NUMBER)  ,"wrong version number"},
 {ERR_REASON(SSL_R_X509_LIB)              ,"x509 lib"},
index 114ad47..3f60ab1 100644 (file)
@@ -2185,12 +2185,13 @@ void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher)
 
 #ifndef OPENSSL_NO_EC
 
-int ssl_check_srvr_ecc_cert_and_alg(X509 *x, const SSL_CIPHER *cs)
+int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s)
        {
        unsigned long alg_k, alg_a;
        EVP_PKEY *pkey = NULL;
        int keysize = 0;
        int signature_nid = 0;
+       const SSL_CIPHER *cs = s->s3->tmp.new_cipher;
 
        alg_k = cs->algorithm_mkey;
        alg_a = cs->algorithm_auth;
@@ -2217,7 +2218,7 @@ int ssl_check_srvr_ecc_cert_and_alg(X509 *x, const SSL_CIPHER *cs)
                        SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG, SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT);
                        return 0;
                        }
-               if (alg_k & SSL_kECDHe)
+               if ((alg_k & SSL_kECDHe) && s->version < TLS1_2_VERSION)
                        {
                        /* signature alg must be ECDSA */
                        if (signature_nid != NID_ecdsa_with_SHA1)
@@ -2226,7 +2227,7 @@ int ssl_check_srvr_ecc_cert_and_alg(X509 *x, const SSL_CIPHER *cs)
                                return 0;
                                }
                        }
-               if (alg_k & SSL_kECDHr)
+               if ((alg_k & SSL_kECDHr) && s->version < TLS1_2_VERSION)
                        {
                        /* signature alg must be RSA */
 
index 3225d65..78958d4 100644 (file)
@@ -1050,7 +1050,7 @@ int ssl3_alert_code(int code);
 int ssl_ok(SSL *s);
 
 #ifndef OPENSSL_NO_ECDH
-int ssl_check_srvr_ecc_cert_and_alg(X509 *x, const SSL_CIPHER *cs);
+int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s);
 #endif
 
 SSL_COMP *ssl3_comp_find(STACK_OF(SSL_COMP) *sk, int n);
@@ -1077,6 +1077,12 @@ int ssl_check_serverhello_tlsext(SSL *s);
 #endif
 int tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
                                const unsigned char *limit, SSL_SESSION **ret);
+
+int tls12_get_sigandhash(unsigned char *p, const EVP_PKEY *pk,
+                               const EVP_MD *md);
+int tls12_get_sigid(const EVP_PKEY *pk);
+const EVP_MD *tls12_get_hash(unsigned char hash_alg);
+
 #endif
 EVP_MD_CTX* ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md) ;
 void ssl_clear_hash_ctx(EVP_MD_CTX **hash);
@@ -1090,4 +1096,3 @@ 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 95a5b35..c60bccd 100644 (file)
@@ -1008,6 +1008,7 @@ int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
        const void *co = NULL, *so = NULL;
        int col = 0, sol = 0;
 
+
 #ifdef KSSL_DEBUG
        printf ("tls1_generate_master_secret(%p,%p, %p, %d)\n", s,out, p,len);
 #endif /* KSSL_DEBUG */
@@ -1032,6 +1033,16 @@ int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
                so, sol,
                p,len,
                s->session->master_key,buff,sizeof buff);
+#ifdef SSL_DEBUG
+       fprintf(stderr, "Premaster Secret:\n");
+       BIO_dump_fp(stderr, (char *)p, len);
+       fprintf(stderr, "Client Random:\n");
+       BIO_dump_fp(stderr, (char *)s->s3->client_random, SSL3_RANDOM_SIZE);
+       fprintf(stderr, "Server Random:\n");
+       BIO_dump_fp(stderr, (char *)s->s3->server_random, SSL3_RANDOM_SIZE);
+       fprintf(stderr, "Master Secret:\n");
+       BIO_dump_fp(stderr, (char *)s->session->master_key, SSL3_MASTER_SECRET_SIZE);
+#endif
 
 #ifdef KSSL_DEBUG
        printf ("tls1_generate_master_secret() complete\n");
index 67a3f86..ca4b2db 100644 (file)
@@ -451,6 +451,62 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                }
                skip_ext:
 
+       if (s->version >= TLS1_2_VERSION)
+               {
+               /* List of supported signature algorithms and hashes.
+                * Should make this customisable at some point, for
+                * now include everything we support.
+                */
+               static unsigned char sigalgs[] = {
+#ifndef OPENSSL_NO_RSA
+# ifndef OPENSSL_NO_SHA512
+                       TLSEXT_hash_sha512, TLSEXT_signature_rsa,
+                       TLSEXT_hash_sha384, TLSEXT_signature_rsa,
+# endif
+# ifndef OPENSSL_NO_SHA256
+                       TLSEXT_hash_sha256, TLSEXT_signature_rsa,
+                       TLSEXT_hash_sha224, TLSEXT_signature_rsa,
+# endif
+# ifndef OPENSSL_NO_SHA
+                       TLSEXT_hash_sha1, TLSEXT_signature_rsa,
+# endif
+#endif
+#ifndef OPENSSL_NO_ECDSA
+# ifndef OPENSSL_NO_SHA512
+                       TLSEXT_hash_sha512, TLSEXT_signature_ecdsa,
+                       TLSEXT_hash_sha384, TLSEXT_signature_ecdsa,
+# endif
+# ifndef OPENSSL_NO_SHA256
+                       TLSEXT_hash_sha256, TLSEXT_signature_ecdsa,
+                       TLSEXT_hash_sha224, TLSEXT_signature_ecdsa,
+# endif
+# ifndef OPENSSL_NO_SHA
+                       TLSEXT_hash_sha1, TLSEXT_signature_ecdsa,
+# endif
+#endif
+#ifndef OPENSSL_NO_DSA
+# ifndef OPENSSL_NO_SHA512
+                       TLSEXT_hash_sha512, TLSEXT_signature_dsa,
+                       TLSEXT_hash_sha384, TLSEXT_signature_dsa,
+# endif
+# ifndef OPENSSL_NO_SHA256
+                       TLSEXT_hash_sha256, TLSEXT_signature_dsa,
+                       TLSEXT_hash_sha224, TLSEXT_signature_dsa,
+# endif
+# ifndef OPENSSL_NO_SHA
+                       TLSEXT_hash_sha1, TLSEXT_signature_dsa
+# endif
+#endif
+               };
+               if ((size_t)(limit - ret) < sizeof(sigalgs) + 6)
+                       return NULL; 
+               s2n(TLSEXT_TYPE_signature_algorithms,ret);
+               s2n(sizeof(sigalgs) + 2, ret);
+               s2n(sizeof(sigalgs), ret);
+               memcpy(ret, sigalgs, sizeof(sigalgs));
+               ret += sizeof(sigalgs);
+               }
+
 #ifdef TLSEXT_TYPE_opaque_prf_input
        if (s->s3->client_opaque_prf_input != NULL &&
            s->version != DTLS1_VERSION)
@@ -1976,15 +2032,15 @@ static int tls12_find_nid(int id, tls12_lookup *table, size_t tlen)
        return -1;
        }
 #endif
-int tls12_get_sigandhash(unsigned char *p, EVP_PKEY *pk, const EVP_MD *md)
+
+int tls12_get_sigandhash(unsigned char *p, const 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));
+       sig_id = tls12_get_sigid(pk);
        if (sig_id == -1)
                return 0;
        p[0] = (unsigned char)md_id;
@@ -1992,9 +2048,47 @@ int tls12_get_sigandhash(unsigned char *p, EVP_PKEY *pk, const EVP_MD *md)
        return 1;
        }
 
+int tls12_get_sigid(const EVP_PKEY *pk)
+       {
+       return tls12_find_id(pk->type, tls12_sig,
+                               sizeof(tls12_sig)/sizeof(tls12_lookup));
+       }
+
+const EVP_MD *tls12_get_hash(unsigned char hash_alg)
+       {
+       switch(hash_alg)
+               {
+#ifndef OPENSSL_NO_MD5
+               case TLSEXT_hash_md5:
+               return EVP_md5();
+#endif
+#ifndef OPENSSL_NO_SHA
+               case TLSEXT_hash_sha1:
+               return EVP_sha1();
+#endif
+#ifndef OPENSSL_NO_SHA256
+               case TLSEXT_hash_sha224:
+               return EVP_sha224();
+
+               case TLSEXT_hash_sha256:
+               return EVP_sha256();
+#endif
+#ifndef OPENSSL_NO_SHA512
+               case TLSEXT_hash_sha384:
+               return EVP_sha384();
+
+               case TLSEXT_hash_sha512:
+               return EVP_sha512();
+#endif
+               default:
+               return NULL;
+
+               }
+       }
+
 /* Set preferred digest for each key type */
 
-int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
+static int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
        {
        int i, idx;
        const EVP_MD *md;
@@ -2033,48 +2127,17 @@ int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
                        continue;
                        }
 
-               if (c->pkeys[idx].digest)
-                       continue;
-
-               switch(hash_alg)
+               if (c->pkeys[idx].digest == NULL)
                        {
-#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;
-
+                       md = tls12_get_hash(hash_alg);
+                       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