Fix warnings.
[openssl.git] / ssl / s3_lib.c
index 0537a16743cff7527a8e67c1ba1c418cabbc0123..7a87da6105c063810738b41e1f6b3ba0bd2b2964 100644 (file)
 #include <openssl/objects.h>
 #include "ssl_locl.h"
 #include "kssl_lcl.h"
+#ifndef OPENSSL_NO_TLSEXT
+#ifndef OPENSSL_NO_EC
+#include "../crypto/ec/ec_lcl.h"
+#endif /* OPENSSL_NO_EC */
+#endif /* OPENSSL_NO_TLSEXT */
 #include <openssl/md5.h>
 #ifndef OPENSSL_NO_DH
 #include <openssl/dh.h>
@@ -1754,30 +1759,6 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
                        }
                s->options |= SSL_OP_NO_SSLv2; /* can't use extension w/ SSL 2.0 format */
                break;
-#ifndef OPENSSL_NO_EC
-       case SSL_CTRL_SET_TLSEXT_ECPOINTFORMATLIST:
-               if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(larg)) == NULL)
-                       {
-                       SSLerr(SSL_F_SSL3_CTRL, ERR_R_MALLOC_FAILURE);
-                       return 0;
-                       }
-               {
-               int i;
-               unsigned char *sparg = (unsigned char *) parg;
-               for (i = 0; i < larg; i++, sparg++)
-                       {
-                       if (TLSEXT_ECPOINTFORMAT_last < *sparg)
-                               {
-                               SSLerr(SSL_F_SSL3_CTRL, SSL_R_SSL3_EXT_INVALID_ECPOINTFORMAT);
-                               return(0);
-                               }
-                       }
-               }
-               s->tlsext_ecpointformatlist_length = larg;
-               memcpy(s->tlsext_ecpointformatlist, parg, larg);
-               s->options |= SSL_OP_NO_SSLv2; /* can't use extension w/ SSL 2.0 format */
-               break;
-#endif /* OPENSSL_NO_EC */
 #endif /* !OPENSSL_NO_TLSEXT */
        default:
                break;
@@ -2062,7 +2043,14 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
        {
        SSL_CIPHER *c,*ret=NULL;
        STACK_OF(SSL_CIPHER) *prio, *allow;
-       int i,j,ok;
+       int i,ok;
+       unsigned int j;
+#ifndef OPENSSL_NO_TLSEXT
+#ifndef OPENSSL_NO_EC
+       int ec_ok, ec_nid;
+       unsigned char ec_search1 = 0, ec_search2 = 0;
+#endif /* OPENSSL_NO_EC */
+#endif /* OPENSSL_NO_TLSEXT */
        CERT *cert;
        unsigned long alg,mask,emask;
 
@@ -2148,6 +2136,160 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
 #endif
                        }
 
+#ifndef OPENSSL_NO_TLSEXT
+#ifndef OPENSSL_NO_EC
+               if (
+                       /* if we are considering an ECC cipher suite that uses our certificate */
+                       (alg & SSL_aECDSA)
+                       /* and we have an ECC certificate */
+                       && (s->cert->pkeys[SSL_PKEY_ECC].x509 != NULL)
+                       /* and the client specified a Supported Point Formats extension */
+                       && ((s->session->tlsext_ecpointformatlist_length > 0) && (s->session->tlsext_ecpointformatlist != NULL))
+                       /* and our certificate's point is compressed */
+                       && (
+                               (s->cert->pkeys[SSL_PKEY_ECC].x509->cert_info != NULL)
+                               && (s->cert->pkeys[SSL_PKEY_ECC].x509->cert_info->key != NULL)
+                               && (s->cert->pkeys[SSL_PKEY_ECC].x509->cert_info->key->public_key != NULL)
+                               && (s->cert->pkeys[SSL_PKEY_ECC].x509->cert_info->key->public_key->data != NULL)
+                               && (
+                                       (*(s->cert->pkeys[SSL_PKEY_ECC].x509->cert_info->key->public_key->data) == POINT_CONVERSION_COMPRESSED)
+                                       || (*(s->cert->pkeys[SSL_PKEY_ECC].x509->cert_info->key->public_key->data) == POINT_CONVERSION_COMPRESSED + 1)
+                                       )
+                               )
+               )
+                       {
+                       ec_ok = 0;
+                       /* if our certificate's curve is over a field type that the client does not support
+                        * then do not allow this cipher suite to be negotiated */
+                       if (
+                               (s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec != NULL)
+                               && (s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group != NULL)
+                               && (s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group->meth != NULL)
+                               && (EC_METHOD_get_field_type(s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group->meth) == NID_X9_62_prime_field)
+                       )
+                               {
+                               for (j = 0; j < s->session->tlsext_ecpointformatlist_length; j++)
+                                       {
+                                       if (s->session->tlsext_ecpointformatlist[j] == TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime)
+                                               {
+                                               ec_ok = 1;
+                                               break;
+                                               }
+                                       }
+                               }
+                       else if (EC_METHOD_get_field_type(s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group->meth) == NID_X9_62_characteristic_two_field)
+                               {
+                               for (j = 0; j < s->session->tlsext_ecpointformatlist_length; j++)
+                                       {
+                                       if (s->session->tlsext_ecpointformatlist[j] == TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2)
+                                               {
+                                               ec_ok = 1;
+                                               break;
+                                               }
+                                       }
+                               }
+                       ok = ok && ec_ok;
+                       }
+               if (
+                       /* if we are considering an ECC cipher suite that uses our certificate */
+                       (alg & SSL_aECDSA)
+                       /* and we have an ECC certificate */
+                       && (s->cert->pkeys[SSL_PKEY_ECC].x509 != NULL)
+                       /* and the client specified an EllipticCurves extension */
+                       && ((s->session->tlsext_ellipticcurvelist_length > 0) && (s->session->tlsext_ellipticcurvelist != NULL))
+               )
+                       {
+                       ec_ok = 0;
+                       if (
+                               (s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec != NULL)
+                               && (s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group != NULL)
+                       )
+                               {
+                               ec_nid = EC_GROUP_get_curve_name(s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group);
+                               if ((ec_nid == 0)
+                                       && (s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group->meth != NULL)
+                               )
+                                       {
+                                       if (EC_METHOD_get_field_type(s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group->meth) == NID_X9_62_prime_field)
+                                               {
+                                               ec_search1 = 0xFF;
+                                               ec_search2 = 0x01;
+                                               }
+                                       else if (EC_METHOD_get_field_type(s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group->meth) == NID_X9_62_characteristic_two_field)
+                                               {
+                                               ec_search1 = 0xFF;
+                                               ec_search2 = 0x02;
+                                               }
+                                       }
+                               else
+                                       {
+                                       ec_search1 = 0x00;
+                                       ec_search2 = tls1_ec_nid2curve_id(ec_nid);
+                                       }
+                               if ((ec_search1 != 0) || (ec_search2 != 0))
+                                       {
+                                       for (j = 0; j < s->session->tlsext_ellipticcurvelist_length / 2; j++)
+                                               {
+                                               if ((s->session->tlsext_ellipticcurvelist[2*j] == ec_search1) && (s->session->tlsext_ellipticcurvelist[2*j+1] == ec_search2))
+                                                       {
+                                                       ec_ok = 1;
+                                                       break;
+                                                       }
+                                               }
+                                       }
+                               }
+                       ok = ok && ec_ok;
+                       }
+               if (
+                       /* if we are considering an ECC cipher suite that uses an ephemeral EC key */
+                       ((alg & SSL_kECDH) || (alg & SSL_kECDHE))
+                       /* and we have an ephemeral EC key */
+                       && (s->cert->ecdh_tmp != NULL)
+                       /* and the client specified an EllipticCurves extension */
+                       && ((s->session->tlsext_ellipticcurvelist_length > 0) && (s->session->tlsext_ellipticcurvelist != NULL))
+               )
+                       {
+                       ec_ok = 0;
+                       if (s->cert->ecdh_tmp->group != NULL)
+                               {
+                               ec_nid = EC_GROUP_get_curve_name(s->cert->ecdh_tmp->group);
+                               if ((ec_nid == 0)
+                                       && (s->cert->ecdh_tmp->group->meth != NULL)
+                               )
+                                       {
+                                       if (EC_METHOD_get_field_type(s->cert->ecdh_tmp->group->meth) == NID_X9_62_prime_field)
+                                               {
+                                               ec_search1 = 0xFF;
+                                               ec_search2 = 0x01;
+                                               }
+                                       else if (EC_METHOD_get_field_type(s->cert->ecdh_tmp->group->meth) == NID_X9_62_characteristic_two_field)
+                                               {
+                                               ec_search1 = 0xFF;
+                                               ec_search2 = 0x02;
+                                               }
+                                       }
+                               else
+                                       {
+                                       ec_search1 = 0x00;
+                                       ec_search2 = tls1_ec_nid2curve_id(ec_nid);
+                                       }
+                               if ((ec_search1 != 0) || (ec_search2 != 0))
+                                       {
+                                       for (j = 0; j < s->session->tlsext_ellipticcurvelist_length / 2; j++)
+                                               {
+                                               if ((s->session->tlsext_ellipticcurvelist[2*j] == ec_search1) && (s->session->tlsext_ellipticcurvelist[2*j+1] == ec_search2))
+                                                       {
+                                                       ec_ok = 1;
+                                                       break;
+                                                       }
+                                               }
+                                       }
+                               }
+                       ok = ok && ec_ok;
+                       }
+#endif /* OPENSSL_NO_EC */
+#endif /* OPENSSL_NO_TLSEXT */
+
                if (!ok) continue;
                j=sk_SSL_CIPHER_find(allow,c);
                if (j >= 0)