Add three Suite B modes to TLS code, supporting RFC6460.
authorDr. Stephen Henson <steve@openssl.org>
Wed, 15 Aug 2012 15:15:05 +0000 (15:15 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Wed, 15 Aug 2012 15:15:05 +0000 (15:15 +0000)
15 files changed:
CHANGES
apps/s_server.c
ssl/s23_clnt.c
ssl/s23_srvr.c
ssl/s3_clnt.c
ssl/s3_lib.c
ssl/s3_srvr.c
ssl/ssl.h
ssl/ssl_cert.c
ssl/ssl_ciph.c
ssl/ssl_err.c
ssl/ssl_lib.c
ssl/ssl_locl.h
ssl/t1_lib.c
ssl/tls1.h

diff --git a/CHANGES b/CHANGES
index f37e3d7..0352bce 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,12 @@
 
  Changes between 1.0.1 and 1.1.0  [xx XXX xxxx]
 
+  *) New Suite B modes for TLS code. These use and enforce the requirements
+     of RFC6460: restrict ciphersuites, only permit Suite B algorithms and
+     only use Suite B curves. The Suite B modes can be set by using the
+     strings "SUITEB128", "SUITEB192" or "SUITEB128ONLY" for the cipherstring.
+     [Steve Henson]
+
   *) New chain verification flags for Suite B levels of security. Check
      algorithms are acceptable when flags are set in X509_verify_cert.
      [Steve Henson]
index bbe2492..3924171 100644 (file)
@@ -2623,8 +2623,8 @@ static int init_ssl_connection(SSL *con)
                        BIO_printf(bio_err,"verify error:%s\n",
                                X509_verify_cert_error_string(verify_error));
                        }
-               else
-                       ERR_print_errors(bio_err);
+               /* Always print any error messages */
+               ERR_print_errors(bio_err);
                return(0);
                }
 
index 807dd0b..20a8b3b 100644 (file)
@@ -367,6 +367,12 @@ static int ssl23_client_hello(SSL *s)
                        version_major = TLS1_2_VERSION_MAJOR;
                        version_minor = TLS1_2_VERSION_MINOR;
                        }
+               else if (tls1_suiteb(s))
+                       {
+                       SSLerr(SSL_F_SSL23_CLIENT_HELLO,
+                                       SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE);
+                       return -1;
+                       }
                else if (version == TLS1_1_VERSION)
                        {
                        version_major = TLS1_1_VERSION_MAJOR;
index 4877849..9d47c22 100644 (file)
@@ -425,6 +425,13 @@ int ssl23_get_client_hello(SSL *s)
                        }
                }
 
+       if (s->version < TLS1_2_VERSION && tls1_suiteb(s))
+               {
+               SSLerr(SSL_F_SSL23_GET_CLIENT_HELLO,
+                               SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE);
+               goto err;
+               }
+
 #ifdef OPENSSL_FIPS
        if (FIPS_mode() && (s->version < TLS1_VERSION))
                {
index 5adbb50..721c3ba 100644 (file)
@@ -3154,8 +3154,9 @@ err:
        }
 
 /* Check a certificate can be used for client authentication. Currently
- * check cert exists, if we have a suitable digest for TLS 1.2  and if
- * static DH client certificates can be used.
+ * check cert exists, if we have a suitable digest for TLS 1.2 if
+ * static DH client certificates can be used and optionally checks
+ * suitability for Suite B.
  */
 static int ssl3_check_client_certificate(SSL *s)
        {
@@ -3165,6 +3166,12 @@ static int ssl3_check_client_certificate(SSL *s)
        /* If no suitable signature algorithm can't use certificate */
        if (TLS1_get_version(s) >= TLS1_2_VERSION && !s->cert->key->digest)
                return 0;
+       /* If strict mode check suitability of chain before using it.
+        * This also adjusts suite B digest if necessary.
+        */
+       if (s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT &&
+               !tls1_check_chain(s, NULL, NULL, NULL, -2))
+               return 0;
        alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
        /* See if we can use client certificate for fixed DH */
        if (alg_k & (SSL_kDHr|SSL_kDHd))
index 3bc5ce9..0147e41 100644 (file)
@@ -3966,7 +3966,7 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
            }
 #endif
 
-       if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE)
+       if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE || tls1_suiteb(s))
                {
                prio = srvr;
                allow = clnt;
@@ -4040,7 +4040,7 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
                /* if we are considering an ECC cipher suite that uses
                 * an ephemeral EC key check it */
                if (alg_k & SSL_kEECDH)
-                       ok = ok && tls1_check_ec_tmp_key(s);
+                       ok = ok && tls1_check_ec_tmp_key(s, c->id);
 #endif /* OPENSSL_NO_EC */
 #endif /* OPENSSL_NO_TLSEXT */
 
@@ -4059,7 +4059,7 @@ int ssl3_get_req_cert_type(SSL *s, unsigned char *p)
        {
        int ret=0;
        const unsigned char *sig;
-       size_t siglen;
+       size_t i, siglen;
        int have_rsa_sign = 0, have_dsa_sign = 0, have_ecdsa_sign = 0;
        int nostrict = 1;
        unsigned long alg_k;
@@ -4070,48 +4070,27 @@ int ssl3_get_req_cert_type(SSL *s, unsigned char *p)
                memcpy(p, s->cert->ctypes, s->cert->ctype_num);
                return (int)s->cert->ctype_num;
                }
-       /* Else see if we have any signature algorithms configured */
-       if (s->cert->client_sigalgs)
+       /* get configured sigalgs */
+       siglen = tls12_get_psigalgs(s, &sig);
+       if (s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT)
+               nostrict = 0;
+       for (i = 0; i < siglen; i+=2, sig+=2)
                {
-               sig = s->cert->client_sigalgs;
-               siglen = s->cert->client_sigalgslen;
-               }
-       else
-               {
-               sig = s->cert->conf_sigalgs;
-               siglen = s->cert->conf_sigalgslen;
-               }
-       /* If we have sigalgs work out if we can sign with RSA, DSA, ECDSA */
-       if (sig)
-               {
-               size_t i;
-               if (s->cert->cert_flags & SSL_CERT_FLAG_TLS_STRICT)
-                       nostrict = 0;
-               for (i = 0; i < siglen; i+=2, sig+=2)
+               switch(sig[1])
                        {
-                       switch(sig[1])
-                               {
-                       case TLSEXT_signature_rsa:
-                               have_rsa_sign = 1;
-                               break;
+               case TLSEXT_signature_rsa:
+                       have_rsa_sign = 1;
+                       break;
 
-                       case TLSEXT_signature_dsa:
-                               have_dsa_sign = 1;
-                               break;
+               case TLSEXT_signature_dsa:
+                       have_dsa_sign = 1;
+                       break;
 
-                       case TLSEXT_signature_ecdsa:
-                               have_ecdsa_sign = 1;
-                               break;
-                               }
+               case TLSEXT_signature_ecdsa:
+                       have_ecdsa_sign = 1;
+                       break;
                        }
                }
-       /* Otherwise allow anything */
-       else
-               {
-               have_rsa_sign = 1;
-               have_dsa_sign = 1;
-               have_ecdsa_sign = 1;
-               }
 
        alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
 
index 2f23f21..76f49f7 100644 (file)
@@ -1704,8 +1704,8 @@ int ssl3_send_server_key_exchange(SSL *s)
                        ecdhp=cert->ecdh_tmp;
                        if (s->cert->ecdh_tmp_auto)
                                {
-                               /* Get NID of first shared curve */
-                               int nid = tls1_shared_curve(s, 0);
+                               /* Get NID of appropriate shared curve */
+                               int nid = tls1_shared_curve(s, -2);
                                if (nid != NID_undef)
                                        ecdhp = EC_KEY_new_by_curve_name(nid);
                                }
index 78ead35..d1104fa 100644 (file)
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -654,7 +654,16 @@ struct ssl_session_st
 /* Many implementations ignore some aspects of the TLS standards such as
  * enforcing certifcate chain algorithms. When this is set we enforce them.
  */
-#define SSL_CERT_FLAG_TLS_STRICT       0x00000001L
+#define SSL_CERT_FLAG_TLS_STRICT               0x00000001L
+
+/* Suite B modes, takes same values as certificate verify flags */
+#define SSL_CERT_FLAG_SUITEB_128_LOS_ONLY      0x10000
+/* Suite B 192 bit only mode */
+#define SSL_CERT_FLAG_SUITEB_192_LOS           0x20000
+/* Suite B 128 bit mode allowing 192 bit algorithms */
+#define SSL_CERT_FLAG_SUITEB_128_LOS           0x30000
+
+
 
 /* Flags for building certificate chains */
 /* Treat any existing certificates as untrusted CAs */
@@ -681,6 +690,8 @@ struct ssl_session_st
 #define CERT_PKEY_ISSUER_NAME  0x200
 /* Cert type matches client types (always set for server cert) */
 #define CERT_PKEY_CERT_TYPE    0x400
+/* Cert chain suitable to Suite B */
+#define CERT_PKEY_SUITEB       0x800
 
 /* Note: SSL[_CTX]_set_{options,mode} use |= op on the previous value,
  * they cannot be used to clear bits. */
@@ -2579,6 +2590,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_R_HTTPS_PROXY_REQUEST                       155
 #define SSL_R_HTTP_REQUEST                              156
 #define SSL_R_ILLEGAL_PADDING                           283
+#define SSL_R_ILLEGAL_SUITEB_DIGEST                     380
 #define SSL_R_INCONSISTENT_COMPRESSION                  340
 #define SSL_R_INVALID_AUDIT_PROOF                       371
 #define SSL_R_INVALID_AUTHZ_DATA                        374
@@ -2653,6 +2665,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_R_NULL_SSL_METHOD_PASSED                    196
 #define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED           197
 #define SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED 344
+#define SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE       379
 #define SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE             297
 #define SSL_R_OPAQUE_PRF_INPUT_TOO_LONG                         327
 #define SSL_R_PACKET_LENGTH_TOO_LONG                    198
index 470ac17..6dfde2f 100644 (file)
@@ -692,6 +692,8 @@ int ssl_verify_cert_chain(SSL *s,STACK_OF(X509) *sk)
                SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN,ERR_R_X509_LIB);
                return(0);
                }
+       /* Set suite B flags if needed */
+       X509_STORE_CTX_set_flags(&ctx, tls1_suiteb(s));
 #if 0
        if (SSL_get_verify_depth(s) >= 0)
                X509_STORE_CTX_set_depth(&ctx, SSL_get_verify_depth(s));
@@ -1151,6 +1153,8 @@ int ssl_build_cert_chain(CERT *c, X509_STORE *chain_store, int flags)
                SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, ERR_R_X509_LIB);
                return 0;
                }
+       /* Set suite B flags if needed */
+       X509_STORE_CTX_set_flags(&xs_ctx, c->cert_flags & SSL_CERT_FLAG_SUITEB_128_LOS);
 
        i = X509_verify_cert(&xs_ctx);
        if (i > 0)
index 6db2aa9..e00c452 100644 (file)
@@ -1347,10 +1347,49 @@ static int ssl_cipher_process_rulestr(const char *rule_str,
        return(retval);
        }
 
+static int check_suiteb_cipher_list(const SSL_METHOD *meth, CERT *c,
+                                       const char **prule_str)
+       {
+       unsigned int suiteb_flags = 0;
+       if (!strcmp(*prule_str, "SUITEB128"))
+               suiteb_flags = SSL_CERT_FLAG_SUITEB_128_LOS;
+       else if (!strcmp(*prule_str, "SUITEB128ONLY"))
+               suiteb_flags = SSL_CERT_FLAG_SUITEB_128_LOS_ONLY;
+       else if (!strcmp(*prule_str, "SUITEB192"))
+               suiteb_flags = SSL_CERT_FLAG_SUITEB_192_LOS;
+
+       if (suiteb_flags)
+               {
+               c->cert_flags &= ~SSL_CERT_FLAG_SUITEB_128_LOS;
+               c->cert_flags |= suiteb_flags;
+               }
+       else
+               suiteb_flags = c->cert_flags & SSL_CERT_FLAG_SUITEB_128_LOS;
+
+       if (!suiteb_flags)
+               return 1;
+       /* Check version */
+
+       switch(suiteb_flags)
+               {
+       case SSL_CERT_FLAG_SUITEB_128_LOS:
+               *prule_str = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384";
+               break;
+       case SSL_CERT_FLAG_SUITEB_128_LOS_ONLY:
+               *prule_str = "ECDHE-ECDSA-AES128-GCM-SHA256";
+               break;
+       case SSL_CERT_FLAG_SUITEB_192_LOS:
+               *prule_str = "ECDHE-ECDSA-AES256-GCM-SHA384";
+               break;
+               }
+       return 1;
+       }
+
+
 STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method,
                STACK_OF(SSL_CIPHER) **cipher_list,
                STACK_OF(SSL_CIPHER) **cipher_list_by_id,
-               const char *rule_str)
+               const char *rule_str, CERT *c)
        {
        int ok, num_of_ciphers, num_of_alias_max, num_of_group_aliases;
        unsigned long disabled_mkey, disabled_auth, disabled_enc, disabled_mac, disabled_ssl;
@@ -1365,6 +1404,10 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method,
        if (rule_str == NULL || cipher_list == NULL || cipher_list_by_id == NULL)
                return NULL;
 
+       if (!check_suiteb_cipher_list(ssl_method, c, &rule_str))
+               return NULL;
+
+
        /*
         * To reduce the work to do we only want to process the compiled
         * in algorithms, so we first get the mask of disabled ciphers.
index 14e8488..4a7d7f2 100644 (file)
@@ -398,6 +398,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {ERR_REASON(SSL_R_HTTPS_PROXY_REQUEST)   ,"https proxy request"},
 {ERR_REASON(SSL_R_HTTP_REQUEST)          ,"http request"},
 {ERR_REASON(SSL_R_ILLEGAL_PADDING)       ,"illegal padding"},
+{ERR_REASON(SSL_R_ILLEGAL_SUITEB_DIGEST) ,"illegal Suite B digest"},
 {ERR_REASON(SSL_R_INCONSISTENT_COMPRESSION),"inconsistent compression"},
 {ERR_REASON(SSL_R_INVALID_AUDIT_PROOF)   ,"invalid audit proof"},
 {ERR_REASON(SSL_R_INVALID_AUTHZ_DATA)    ,"invalid authz data"},
@@ -472,6 +473,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {ERR_REASON(SSL_R_NULL_SSL_METHOD_PASSED),"null ssl method passed"},
 {ERR_REASON(SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED),"old session cipher not returned"},
 {ERR_REASON(SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED),"old session compression algorithm not returned"},
+{ERR_REASON(SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE),"only TLS 1.2 allowed in Suite B mode"},
 {ERR_REASON(SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE),"only tls allowed in fips mode"},
 {ERR_REASON(SSL_R_OPAQUE_PRF_INPUT_TOO_LONG),"opaque PRF input too long"},
 {ERR_REASON(SSL_R_PACKET_LENGTH_TOO_LONG),"packet length too long"},
index bec87d8..548ba1c 100644 (file)
@@ -263,7 +263,7 @@ int SSL_CTX_set_ssl_version(SSL_CTX *ctx,const SSL_METHOD *meth)
 
        sk=ssl_create_cipher_list(ctx->method,&(ctx->cipher_list),
                &(ctx->cipher_list_by_id),
-               meth->version == SSL2_VERSION ? "SSLv2" : SSL_DEFAULT_CIPHER_LIST);
+               meth->version == SSL2_VERSION ? "SSLv2" : SSL_DEFAULT_CIPHER_LIST, ctx->cert);
        if ((sk == NULL) || (sk_SSL_CIPHER_num(sk) <= 0))
                {
                SSLerr(SSL_F_SSL_CTX_SET_SSL_VERSION,SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS);
@@ -1333,7 +1333,7 @@ int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str)
        STACK_OF(SSL_CIPHER) *sk;
        
        sk=ssl_create_cipher_list(ctx->method,&ctx->cipher_list,
-               &ctx->cipher_list_by_id,str);
+               &ctx->cipher_list_by_id,str, ctx->cert);
        /* ssl_create_cipher_list may return an empty stack if it
         * was unable to find a cipher matching the given rule string
         * (for example if the rule string specifies a cipher which
@@ -1357,7 +1357,7 @@ int SSL_set_cipher_list(SSL *s,const char *str)
        STACK_OF(SSL_CIPHER) *sk;
        
        sk=ssl_create_cipher_list(s->ctx->method,&s->cipher_list,
-               &s->cipher_list_by_id,str);
+               &s->cipher_list_by_id,str, s->cert);
        /* see comment in SSL_CTX_set_cipher_list */
        if (sk == NULL)
                return 0;
@@ -1787,7 +1787,7 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
 
        ssl_create_cipher_list(ret->method,
                &ret->cipher_list,&ret->cipher_list_by_id,
-               meth->version == SSL2_VERSION ? "SSLv2" : SSL_DEFAULT_CIPHER_LIST);
+               meth->version == SSL2_VERSION ? "SSLv2" : SSL_DEFAULT_CIPHER_LIST, ret->cert);
        if (ret->cipher_list == NULL
            || sk_SSL_CIPHER_num(ret->cipher_list) <= 0)
                {
index 1523303..39ee16b 100644 (file)
@@ -489,6 +489,11 @@ typedef struct cert_pkey_st
         */
        int valid_flags;
        } CERT_PKEY;
+/* Retrieve Suite B flags */
+#define tls1_suiteb(s) (s->cert->cert_flags & SSL_CERT_FLAG_SUITEB_128_LOS)
+/* Uses to check strict mode: suite B modes are always strict */
+#define SSL_CERT_FLAGS_CHECK_TLS_STRICT \
+       (SSL_CERT_FLAG_SUITEB_128_LOS|SSL_CERT_FLAG_TLS_STRICT)
 
 typedef struct cert_st
        {
@@ -910,7 +915,7 @@ int ssl_cipher_list_to_bytes(SSL *s,STACK_OF(SSL_CIPHER) *sk,unsigned char *p,
 STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *meth,
                                             STACK_OF(SSL_CIPHER) **pref,
                                             STACK_OF(SSL_CIPHER) **sorted,
-                                            const char *rule_str);
+                                            const char *rule_str, CERT *c);
 void ssl_update_cache(SSL *s, int mode);
 int ssl_cipher_get_evp(const SSL_SESSION *s,const EVP_CIPHER **enc,
                       const EVP_MD **md,int *mac_pkey_type,int *mac_secret_size, SSL_COMP **comp);
@@ -1184,7 +1189,7 @@ int tls1_set_curves(unsigned char **pext, size_t *pextlen,
                        int *curves, size_t ncurves);
 int tls1_set_curves_list(unsigned char **pext, size_t *pextlen, 
                                const char *str);
-int tls1_check_ec_tmp_key(SSL *s);
+int tls1_check_ec_tmp_key(SSL *s, unsigned long id);
 #endif /* OPENSSL_NO_EC */
 
 #ifndef OPENSSL_NO_TLSEXT
index 68bd709..ecac97b 100644 (file)
@@ -241,6 +241,12 @@ static const unsigned char eccurves_default[] =
                0,17, /* secp160r2 (17) */ 
        };
 
+static const unsigned char suiteb_curves[] =
+       {
+               0, TLSEXT_curve_P_256,
+               0, TLSEXT_curve_P_384
+       };
+
 int tls1_ec_curve_id2nid(int curve_id)
        {
        /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */
@@ -320,13 +326,29 @@ static void tls1_get_curvelist(SSL *s, int sess,
                {
                *pcurves = s->session->tlsext_ellipticcurvelist;
                *pcurveslen = s->session->tlsext_ellipticcurvelist_length;
+               return;
                }
-       else
+       /* For Suite B mode only include P-256, P-384 */
+       switch (tls1_suiteb(s))
                {
+       case SSL_CERT_FLAG_SUITEB_128_LOS:
+               *pcurves = suiteb_curves;
+               *pcurveslen = sizeof(suiteb_curves);
+               break;
+
+       case SSL_CERT_FLAG_SUITEB_128_LOS_ONLY:
+               *pcurves = suiteb_curves;
+               *pcurveslen = 2;
+               break;
+
+       case SSL_CERT_FLAG_SUITEB_192_LOS:
+               *pcurves = suiteb_curves + 2;
+               *pcurveslen = 2;
+               break;
+       default:
                *pcurves = s->tlsext_ellipticcurvelist;
                *pcurveslen = s->tlsext_ellipticcurvelist_length;
                }
-       /* If not set use default: for now static structure */
        if (!*pcurves)
                {
                *pcurves = eccurves_default;
@@ -338,8 +360,28 @@ int tls1_check_curve(SSL *s, const unsigned char *p, size_t len)
        {
        const unsigned char *curves;
        size_t curveslen, i;
+       unsigned int suiteb_flags = tls1_suiteb(s);
        if (len != 3 || p[0] != NAMED_CURVE_TYPE)
                return 0;
+       /* Check curve matches Suite B preferences */
+       if (suiteb_flags)
+               {
+               unsigned long cid = s->s3->tmp.new_cipher->id;
+               if (p[1])
+                       return 0;
+               if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
+                       {
+                       if (p[2] != TLSEXT_curve_P_256)
+                               return 0;
+                       }
+               else if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
+                       {
+                       if (p[2] != TLSEXT_curve_P_384)
+                               return 0;
+                       }
+               else    /* Should never happen */
+                       return 0;
+               }
        tls1_get_curvelist(s, 0, &curves, &curveslen);
        for (i = 0; i < curveslen; i += 2, curves += 2)
                {
@@ -350,7 +392,8 @@ int tls1_check_curve(SSL *s, const unsigned char *p, size_t len)
        }
 
 /* Return nth shared curve. If nmatch == -1 return number of
- * matches.
+ * matches. For nmatch == -2 return the NID of the curve to use for
+ * an EC tmp key.
  */
 
 int tls1_shared_curve(SSL *s, int nmatch)
@@ -361,6 +404,25 @@ int tls1_shared_curve(SSL *s, int nmatch)
        /* Can't do anything on client side */
        if (s->server == 0)
                return -1;
+       if (nmatch == -2)
+               {
+               if (tls1_suiteb(s))
+                       {
+                       /* For Suite B ciphersuite determines curve: we 
+                        * already know these are acceptable due to previous
+                        * checks.
+                        */
+                       unsigned long cid = s->s3->tmp.new_cipher->id;
+                       if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
+                               return NID_X9_62_prime256v1; /* P-256 */
+                       if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
+                               return NID_secp384r1; /* P-384 */
+                       /* Should never happen */
+                       return NID_undef;
+                       }
+               /* If not Suite B just return first preference shared curve */
+               nmatch = 0;
+               }
        tls1_get_curvelist(s, !!(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE),
                                &supp, &supplen);
        tls1_get_curvelist(s, !(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE),
@@ -540,6 +602,8 @@ static int tls1_check_ec_key(SSL *s,
                if (i == plen)
                        return 0;
                }
+       if (!curve_id)
+               return 1;
        /* Check curve is consistent with client and server preferences */
        for (j = 0; j <= 1; j++)
                {
@@ -551,6 +615,9 @@ static int tls1_check_ec_key(SSL *s,
                        }
                if (i == plen)
                        return 0;
+               /* For clients can only check sent curve list */
+               if (!s->server)
+                       return 1;
                }
        return 1;
        }
@@ -558,7 +625,7 @@ static int tls1_check_ec_key(SSL *s,
 /* Check cert parameters compatible with extensions: currently just checks
  * EC certificates have compatible curves and compression.
  */
-static int tls1_check_cert_param(SSL *s, X509 *x)
+static int tls1_check_cert_param(SSL *s, X509 *x, int set_ee_md)
        {
        unsigned char comp_id, curve_id[2];
        EVP_PKEY *pkey;
@@ -576,13 +643,82 @@ static int tls1_check_cert_param(SSL *s, X509 *x)
        EVP_PKEY_free(pkey);
        if (!rv)
                return 0;
-       return tls1_check_ec_key(s, curve_id, &comp_id);
+       /* Can't check curve_id for client certs as we don't have a
+        * supported curves extension.
+        */
+       rv = tls1_check_ec_key(s, s->server ? curve_id : NULL, &comp_id);
+       if (!rv)
+               return 0;
+       /* Special case for suite B. We *MUST* sign using SHA256+P-256 or
+        * SHA384+P-384, adjust digest if necessary.
+        */
+       if (set_ee_md && tls1_suiteb(s))
+               {
+               int check_md;
+               size_t i;
+               CERT *c = s->cert;
+               if (curve_id[0])
+                       return 0;
+               /* Check to see we have necessary signing algorithm */
+               if (curve_id[1] == TLSEXT_curve_P_256)
+                       check_md = NID_ecdsa_with_SHA256;
+               else if (curve_id[1] == TLSEXT_curve_P_384)
+                       check_md = NID_ecdsa_with_SHA384;
+               else
+                       return 0; /* Should never happen */
+               for (i = 0; i < c->shared_sigalgslen; i++)
+                       if (check_md == c->shared_sigalgs[i].signandhash_nid)
+                               break;
+               if (i == c->shared_sigalgslen)
+                       return 0;
+               if (set_ee_md == 2)
+                       {
+                       if (check_md == NID_ecdsa_with_SHA256)
+                               c->pkeys[SSL_PKEY_ECC].digest = EVP_sha256();
+                       else
+                               c->pkeys[SSL_PKEY_ECC].digest = EVP_sha384();
+                       }
+               }
+       return rv;
        }
 /* Check EC temporary key is compatible with client extensions */
-int tls1_check_ec_tmp_key(SSL *s)
+int tls1_check_ec_tmp_key(SSL *s, unsigned long cid)
        {
        unsigned char curve_id[2];
        EC_KEY *ec = s->cert->ecdh_tmp;
+       /* If Suite B, AES128 MUST use P-256 and AES256 MUST use P-384,
+        * no other curves permitted.
+        */
+       if (tls1_suiteb(s))
+               {
+               /* Curve to check determined by ciphersuite */
+               if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
+                       curve_id[1] = TLSEXT_curve_P_256;
+               else if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
+                       curve_id[1] = TLSEXT_curve_P_384;
+               else
+                       return 0;
+               curve_id[0] = 0;
+               /* Check this curve is acceptable */
+               if (!tls1_check_ec_key(s, curve_id, NULL))
+                       return 0;
+               /* If auto or setting curve from callback assume OK */
+               if (s->cert->ecdh_tmp_auto || s->cert->ecdh_tmp_cb)
+                       return 1;
+               /* Otherwise check curve is acceptable */
+               else 
+                       {
+                       unsigned char curve_tmp[2];
+                       if (!ec)
+                               return 0;
+                       if (!tls1_set_ec_id(curve_tmp, NULL, ec))
+                               return 0;
+                       if (!curve_tmp[0] || curve_tmp[1] == curve_id[1])
+                               return 1;
+                       return 0;
+                       }
+                       
+               }
        if (s->cert->ecdh_tmp_auto)
                {
                /* Need a shared curve */
@@ -655,8 +791,31 @@ static unsigned char tls12_sigalgs[] = {
 #endif
 };
 
+static unsigned char suiteb_sigalgs[] = {
+       tlsext_sigalg_ecdsa(TLSEXT_hash_sha256)
+       tlsext_sigalg_ecdsa(TLSEXT_hash_sha384)
+};
+
 size_t tls12_get_psigalgs(SSL *s, const unsigned char **psigs)
        {
+       /* If Suite B mode use Suite B sigalgs only, ignore any other
+        * preferences.
+        */
+       switch (tls1_suiteb(s))
+               {
+       case SSL_CERT_FLAG_SUITEB_128_LOS:
+               *psigs = suiteb_sigalgs;
+               return sizeof(suiteb_sigalgs);
+
+       case SSL_CERT_FLAG_SUITEB_128_LOS_ONLY:
+               *psigs = suiteb_sigalgs;
+               return 2;
+
+       case SSL_CERT_FLAG_SUITEB_192_LOS:
+               *psigs = suiteb_sigalgs + 2;
+               return 2;
+               }
+
        /* If server use client authentication sigalgs if not NULL */
        if (s->server && s->cert->client_sigalgs)
                {
@@ -698,6 +857,44 @@ int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s,
                SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,SSL_R_WRONG_SIGNATURE_TYPE);
                return 0;
                }
+       if (pkey->type == EVP_PKEY_EC)
+               {
+               unsigned char curve_id[2], comp_id;
+               /* Check compression and curve matches extensions */
+               if (!tls1_set_ec_id(curve_id, &comp_id, pkey->pkey.ec))
+                       return 0;
+               if (!s->server && !tls1_check_ec_key(s, curve_id, &comp_id))
+                       return 0;
+               /* If Suite B only P-384+SHA384 or P-256+SHA-256 allowed */
+               if (tls1_suiteb(s))
+                       {
+                       if (curve_id[0])
+                               return 0;
+                       if (curve_id[1] == TLSEXT_curve_P_256)
+                               {
+                               if (sig[0] != TLSEXT_hash_sha256)
+                                       {
+                                       SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,
+                                               SSL_R_ILLEGAL_SUITEB_DIGEST);
+                                       return 0;
+                                       }
+                               }
+                       else if (curve_id[1] == TLSEXT_curve_P_384)
+                               {
+                               if (sig[0] != TLSEXT_hash_sha384)
+                                       {
+                                       SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,
+                                               SSL_R_ILLEGAL_SUITEB_DIGEST);
+                                       return 0;
+                                       }
+                               }
+                       else
+                               return 0;
+                       }
+               }
+       else if (tls1_suiteb(s))
+               return 0;
+
        /* Check signature matches a type we sent */
        sent_sigslen = tls12_get_psigalgs(s, &sent_sigs);
        for (i = 0; i < sent_sigslen; i+=2, sent_sigs+=2)
@@ -706,7 +903,7 @@ int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s,
                        break;
                }
        /* Allow fallback to SHA1 if not strict mode */
-       if (i == sent_sigslen && (sig[0] != TLSEXT_hash_sha1 || s->cert->cert_flags & SSL_CERT_FLAG_TLS_STRICT))
+       if (i == sent_sigslen && (sig[0] != TLSEXT_hash_sha1 || s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT))
                {
                SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,SSL_R_WRONG_SIGNATURE_TYPE);
                return 0;
@@ -3123,27 +3320,21 @@ static int tls1_set_shared_sigalgs(SSL *s)
        size_t nmatch;
        TLS_SIGALGS *salgs = NULL;
        CERT *c = s->cert;
+       unsigned int is_suiteb = tls1_suiteb(s);
        /* If client use client signature algorithms if not NULL */
-       if (!s->server && c->client_sigalgs)
+       if (!s->server && c->client_sigalgs && !is_suiteb)
                {
                conf = c->client_sigalgs;
                conflen = c->client_sigalgslen;
                }
-       else if (c->conf_sigalgs)
+       else if (c->conf_sigalgs && !is_suiteb)
                {
                conf = c->conf_sigalgs;
                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)
+               conflen = tls12_get_psigalgs(s, &conf);
+       if(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE || is_suiteb)
                {
                pref = conf;
                preflen = conflen;
@@ -3214,7 +3405,7 @@ int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
        /* In strict mode leave unset digests as NULL to indicate we can't
         * use the certificate for signing.
         */
-       if (!(s->cert->cert_flags & SSL_CERT_FLAG_TLS_STRICT))
+       if (!(s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT))
                {
                /* Set any remaining keys to default values. NOTE: if alg is
                 * not supported it stays as NULL.
@@ -3588,14 +3779,22 @@ int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain,
        int check_flags = 0, strict_mode;
        CERT_PKEY *cpk = NULL;
        CERT *c = s->cert;
-       /* idx != -1 means checking server chains */
+       unsigned int suiteb_flags = tls1_suiteb(s);
+       /* idx == -1 means checking server chains */
        if (idx != -1)
                {
-               cpk = c->pkeys + idx;
+               /* idx == -2 means checking client certificate chains */
+               if (idx == -2)
+                       {
+                       cpk = c->key;
+                       idx = cpk - c->pkeys;
+                       }
+               else
+                       cpk = c->pkeys + idx;
                x = cpk->x509;
                pk = cpk->privatekey;
                chain = cpk->chain;
-               strict_mode = c->cert_flags & SSL_CERT_FLAG_TLS_STRICT;
+               strict_mode = c->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT;
                /* If no cert or key, forget it */
                if (!x || !pk)
                        goto end;
@@ -3608,13 +3807,27 @@ int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain,
                if (idx == -1)
                        goto end;
                cpk = c->pkeys + idx;
-               if (c->cert_flags & SSL_CERT_FLAG_TLS_STRICT)
+               if (c->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT)
                        check_flags = CERT_PKEY_STRICT_FLAGS;
                else
                        check_flags = CERT_PKEY_VALID_FLAGS;
                strict_mode = 1;
                }
 
+       if (suiteb_flags)
+               {
+               int ok;
+               if (check_flags)
+                       check_flags |= CERT_PKEY_SUITEB;
+               ok = X509_chain_check_suiteb(NULL, x, chain, suiteb_flags);
+               if (ok != X509_V_OK)
+                       {
+                       if (check_flags)
+                               rv |= CERT_PKEY_SUITEB;
+                       else
+                               goto end;
+                       }
+               }
 
        /* Check all signature algorithms are consistent with
         * signature algorithms extension if TLS 1.2 or later
@@ -3702,8 +3915,8 @@ int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain,
        else if(check_flags)
                rv |= CERT_PKEY_EE_SIGNATURE|CERT_PKEY_CA_SIGNATURE;
        skip_sigs:
-       /* Check cert parameters are consistent: server certs only */
-       if (!s->server || tls1_check_cert_param(s, x))
+       /* Check cert parameters are consistent */
+       if (tls1_check_cert_param(s, x, check_flags ? 1 : 2))
                rv |= CERT_PKEY_EE_PARAM;
        else if (!check_flags)
                goto end;
@@ -3715,7 +3928,8 @@ int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain,
                rv |= CERT_PKEY_CA_PARAM;
                for (i = 0; i < sk_X509_num(chain); i++)
                        {
-                       if (!tls1_check_cert_param(s, sk_X509_value(chain, i)))
+                       X509 *ca = sk_X509_value(chain, i);
+                       if (!tls1_check_cert_param(s, ca, 0))
                                {
                                if (check_flags)
                                        {
@@ -3832,7 +4046,11 @@ int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain,
                if (rv & CERT_PKEY_VALID)
                        cpk->valid_flags = rv;
                else
-                       cpk->valid_flags = 0;
+                       {
+                       /* Preserve explicit sign flag, clear rest */
+                       cpk->valid_flags &= CERT_PKEY_EXPLICIT_SIGN;
+                       return 0;
+                       }
                }
        return rv;
        }
index 4d087e0..c59a02f 100644 (file)
@@ -285,6 +285,11 @@ extern "C" {
 /* Flag set for unrecognised algorithms */
 #define TLSEXT_nid_unknown                             0x1000000
 
+/* ECC curves */
+
+#define TLSEXT_curve_P_256                             23
+#define TLSEXT_curve_P_384                             24
+
 #ifndef OPENSSL_NO_TLSEXT
 
 #define TLSEXT_MAXLEN_host_name 255