Implement the Supported Point Formats Extension for ECC ciphersuites
authorBodo Möller <bodo@openssl.org>
Sat, 11 Mar 2006 23:46:37 +0000 (23:46 +0000)
committerBodo Möller <bodo@openssl.org>
Sat, 11 Mar 2006 23:46:37 +0000 (23:46 +0000)
Submitted by: Douglas Stebila

CHANGES
ssl/s3_clnt.c
ssl/s3_lib.c
ssl/s3_srvr.c
ssl/ssl.h
ssl/ssl_asn1.c
ssl/ssl_err.c
ssl/ssl_locl.h
ssl/ssl_sess.c
ssl/t1_lib.c
ssl/tls1.h

diff --git a/CHANGES b/CHANGES
index ffe039b..41aae27 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,10 @@
 
  Changes between 0.9.8a and 0.9.9  [xx XXX xxxx]
 
+  *) Implement the Supported Point Formats Extension for
+     ECC ciphersuites from draft-ietf-tls-ecc-12.txt.
+     [Douglas Stebila]
+
   *) Add initial support for RFC 4279 PSK TLS ciphersuites. Add members
      for the psk identity [hint] and the psk callback functions to the
      SSL_SESSION, SSL and SSL_CTX structure.
index 237dfb6..a8f2b8f 100644 (file)
@@ -632,6 +632,11 @@ int ssl3_client_hello(SSL *s)
 #endif
                *(p++)=0; /* Add the NULL method */
 #ifndef OPENSSL_NO_TLSEXT
+               if (ssl_prepare_clienthello_tlsext(s) <= 0)
+                       {
+                       SSLerr(SSL_F_SSL3_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
+                       goto err;
+                       }
                if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
                        {
                        SSLerr(SSL_F_SSL3_CLIENT_HELLO,ERR_R_INTERNAL_ERROR);
@@ -829,12 +834,12 @@ int ssl3_get_server_hello(SSL *s)
                if (!ssl_parse_serverhello_tlsext(s,&p,d,n, &al))
                        {
                        /* 'al' set by ssl_parse_serverhello_tlsext */
-                       SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_PARSE_TLS_EXT);
+                       SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_PARSE_TLSEXT);
                        goto f_err; 
                        }
-               if (ssl_check_tlsext(s,0) <= 0)
+               if (ssl_check_serverhello_tlsext(s) <= 0)
                        {
-                       SSLerr(SSL_F_SSL3_CONNECT,SSL_R_SERVERHELLO_TLS_EXT);
+                       SSLerr(SSL_F_SSL3_CONNECT,SSL_R_SERVERHELLO_TLSEXT);
                                goto err;
                        }
                }
index aecf6d6..0537a16 100644 (file)
@@ -1754,6 +1754,30 @@ 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;
index 8859540..43ff0d8 100644 (file)
@@ -941,12 +941,12 @@ int ssl3_get_client_hello(SSL *s)
                if (!ssl_parse_clienthello_tlsext(s,&p,d,n, &al))
                        {
                        /* 'al' set by ssl_parse_clienthello_tlsext */
-                       SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PARSE_TLS_EXT);
+                       SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PARSE_TLSEXT);
                        goto f_err;
                        }
                }
-               if (ssl_check_tlsext(s,1) <= 0) {
-                       SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_CLIENTHELLO_TLS_EXT);
+               if (ssl_check_clienthello_tlsext(s) <= 0) {
+                       SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_CLIENTHELLO_TLSEXT);
                        goto err;
                }
 #endif
@@ -1126,6 +1126,11 @@ int ssl3_send_server_hello(SSL *s)
                        *(p++)=s->s3->tmp.new_compression->id;
 #endif
 #ifndef OPENSSL_NO_TLSEXT
+               if (ssl_prepare_serverhello_tlsext(s) <= 0)
+                       {
+                       SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO,SSL_R_SERVERHELLO_TLSEXT);
+                       return -1;
+                       }
                if ((p = ssl_add_serverhello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
                        {
                        SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO,ERR_R_INTERNAL_ERROR);
index 33792ea..4d26c70 100644 (file)
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -507,6 +507,10 @@ typedef struct ssl_session_st
        struct ssl_session_st *prev,*next;
 #ifndef OPENSSL_NO_TLSEXT
        char *tlsext_hostname;
+#ifndef OPENSSL_NO_EC
+       int tlsext_ecpointformatlist_length;
+       char * tlsext_ecpointformatlist;
+#endif /* OPENSSL_NO_EC */
 #endif
        } SSL_SESSION;
 
@@ -1057,6 +1061,10 @@ struct ssl_st
                                  1 : prepare 2, allow last ack just after in server callback.
                                  2 : don't call servername callback, no ack in server hello
                               */
+#ifndef OPENSSL_NO_EC
+       int tlsext_ecpointformatlist_length;
+       char * tlsext_ecpointformatlist;
+#endif /* OPENSSL_NO_EC */
        SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
 #define session_ctx initial_ctx
 #else
@@ -1279,6 +1287,7 @@ size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count);
 #define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB      53
 #define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG     54
 #define SSL_CTRL_SET_TLSEXT_HOSTNAME           55
+#define SSL_CTRL_SET_TLSEXT_ECPOINTFORMATLIST  56
 #endif
 
 #define SSL_session_reused(ssl) \
@@ -1829,7 +1838,10 @@ void ERR_load_SSL_strings(void);
 #define SSL_F_SSL_VERIFY_CERT_CHAIN                     207
 #define SSL_F_SSL_WRITE                                         208
 #define SSL_F_TLS1_CHANGE_CIPHER_STATE                  209
+#define SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT             274
 #define SSL_F_TLS1_ENC                                  210
+#define SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT           275
+#define SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT           276
 #define SSL_F_TLS1_SETUP_KEY_BLOCK                      211
 #define SSL_F_WRITE_PENDING                             212
 
@@ -1880,7 +1892,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_R_CIPHER_CODE_WRONG_LENGTH                  137
 #define SSL_R_CIPHER_OR_HASH_UNAVAILABLE                138
 #define SSL_R_CIPHER_TABLE_SRC_ERROR                    139
-#define SSL_R_CLIENTHELLO_TLS_EXT                       316
+#define SSL_R_CLIENTHELLO_TLSEXT                        226
 #define SSL_R_COMPRESSED_LENGTH_TOO_LONG                140
 #define SSL_R_COMPRESSION_FAILURE                       141
 #define SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE   307
@@ -1965,7 +1977,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED           197
 #define SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE             297
 #define SSL_R_PACKET_LENGTH_TOO_LONG                    198
-#define SSL_R_PARSE_TLS_EXT                             317
+#define SSL_R_PARSE_TLSEXT                              227
 #define SSL_R_PATH_TOO_LONG                             270
 #define SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE                 199
 #define SSL_R_PEER_ERROR                                200
@@ -1992,12 +2004,13 @@ void ERR_load_SSL_strings(void);
 #define SSL_R_REUSE_CERT_LENGTH_NOT_ZERO                216
 #define SSL_R_REUSE_CERT_TYPE_NOT_ZERO                  217
 #define SSL_R_REUSE_CIPHER_LIST_NOT_ZERO                218
-#define SSL_R_SERVERHELLO_TLS_EXT                       318
+#define SSL_R_SERVERHELLO_TLSEXT                        275
 #define SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED          277
 #define SSL_R_SHORT_READ                                219
 #define SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE     220
 #define SSL_R_SSL23_DOING_SESSION_ID_REUSE              221
 #define SSL_R_SSL2_CONNECTION_ID_TOO_LONG               299
+#define SSL_R_SSL3_EXT_INVALID_ECPOINTFORMAT            321
 #define SSL_R_SSL3_EXT_INVALID_SERVERNAME               319
 #define SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE          320
 #define SSL_R_SSL3_SESSION_ID_TOO_LONG                  300
@@ -2039,6 +2052,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_R_TLSV1_UNRECOGNIZED_NAME                   1112
 #define SSL_R_TLSV1_UNSUPPORTED_EXTENSION               1110
 #define SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER      232
+#define SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST            157
 #define SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST 233
 #define SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG   234
 #define SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER           235
index a8193a5..4845499 100644 (file)
@@ -106,6 +106,9 @@ typedef struct ssl_session_asn1_st
        ASN1_INTEGER verify_result;
 #ifndef OPENSSL_NO_TLSEXT
        ASN1_OCTET_STRING tlsext_hostname;
+#ifndef OPENSSL_NO_EC
+       ASN1_OCTET_STRING tlsext_ecpointformatlist;
+#endif /* OPENSSL_NO_EC */
 #endif /* OPENSSL_NO_TLSEXT */
 #ifndef OPENSSL_NO_PSK
        ASN1_OCTET_STRING psk_identity_hint;
@@ -116,7 +119,7 @@ typedef struct ssl_session_asn1_st
 int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
        {
 #define LSIZE2 (sizeof(long)*2)
-       int v1=0,v2=0,v3=0,v4=0,v5=0,v6=0,v7=0,v8=0;
+       int v1=0,v2=0,v3=0,v4=0,v5=0,v6=0,v7=0,v8=0,v9=0;
        unsigned char buf[4],ibuf1[LSIZE2],ibuf2[LSIZE2];
        unsigned char ibuf3[LSIZE2],ibuf4[LSIZE2],ibuf5[LSIZE2];
        long l;
@@ -218,6 +221,20 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
                 a.tlsext_hostname.type=V_ASN1_OCTET_STRING;
                 a.tlsext_hostname.data=(unsigned char *)in->tlsext_hostname;
                 }                
+#ifndef OPENSSL_NO_EC
+       if (in->tlsext_ecpointformatlist)
+               {
+               a.tlsext_ecpointformatlist.length=1+in->tlsext_ecpointformatlist_length;
+               a.tlsext_ecpointformatlist.type=V_ASN1_OCTET_STRING;
+               if ((a.tlsext_ecpointformatlist.data = OPENSSL_malloc(1+in->tlsext_ecpointformatlist_length)) == NULL)
+                       {
+                       SSLerr(SSL_F_I2D_SSL_SESSION,ERR_R_MALLOC_FAILURE);
+                       return(0);
+                       }
+               *a.tlsext_ecpointformatlist.data = (unsigned char) in->tlsext_ecpointformatlist_length;
+               memcpy(a.tlsext_ecpointformatlist.data+1, in->tlsext_ecpointformatlist, in->tlsext_ecpointformatlist_length);
+               }
+#endif /* OPENSSL_NO_EC */
 #endif /* OPENSSL_NO_TLSEXT */
 #ifndef OPENSSL_NO_PSK
        if (in->psk_identity_hint)
@@ -258,12 +275,16 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
 #ifndef OPENSSL_NO_TLSEXT
        if (in->tlsext_hostname)
                M_ASN1_I2D_len_EXP_opt(&(a.tlsext_hostname), i2d_ASN1_OCTET_STRING,6,v6);
+#ifndef OPENSSL_NO_EC
+       if (in->tlsext_ecpointformatlist)
+               M_ASN1_I2D_len_EXP_opt(&(a.tlsext_ecpointformatlist), i2d_ASN1_OCTET_STRING,7,v7);
+#endif /* OPENSSL_NO_EC */
 #endif /* OPENSSL_NO_TLSEXT */
 #ifndef OPENSSL_NO_PSK
        if (in->psk_identity_hint)
-               M_ASN1_I2D_len_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,6,v7);
+               M_ASN1_I2D_len_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,8,v8);
        if (in->psk_identity)
-               M_ASN1_I2D_len_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,7,v8);
+               M_ASN1_I2D_len_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,9,v9);
 #endif /* OPENSSL_NO_PSK */
 
        M_ASN1_I2D_seq_total();
@@ -292,14 +313,23 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
 #ifndef OPENSSL_NO_TLSEXT
        if (in->tlsext_hostname)
                M_ASN1_I2D_put_EXP_opt(&(a.tlsext_hostname), i2d_ASN1_OCTET_STRING,6,v6);
+#ifndef OPENSSL_NO_EC
+       if (in->tlsext_ecpointformatlist)
+               M_ASN1_I2D_put_EXP_opt(&(a.tlsext_ecpointformatlist), i2d_ASN1_OCTET_STRING,7,v7);
+#endif /* OPENSSL_NO_EC */
 #endif /* OPENSSL_NO_TLSEXT */
 #ifndef OPENSSL_NO_PSK
        if (in->psk_identity_hint)
-               M_ASN1_I2D_put_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,6,v6);
+               M_ASN1_I2D_put_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,8,v8);
        if (in->psk_identity)
-               M_ASN1_I2D_put_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,7,v7);
+               M_ASN1_I2D_put_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,9,v9);
 #endif /* OPENSSL_NO_PSK */
        M_ASN1_I2D_finish();
+#ifndef OPENSSL_NO_TLSEXT
+#ifndef OPENSSL_NO_EC
+       OPENSSL_free(a.tlsext_ecpointformatlist.data);
+#endif /* OPENSSL_NO_EC */
+#endif /* OPENSSL_NO_TLSEXT */
        }
 
 SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
@@ -484,12 +514,38 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
        else
                ret->tlsext_hostname=NULL;
 
+#ifndef OPENSSL_NO_EC
+       os.length=0;
+       os.data=NULL;
+       M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,7);
+       if (os.data)
+               {
+               if ((ret->tlsext_ecpointformatlist = OPENSSL_malloc(os.length - 1)) == NULL)
+                       {
+                       SSLerr(SSL_F_D2I_SSL_SESSION,ERR_R_MALLOC_FAILURE);
+                       }
+               else
+                       {
+                       ret->tlsext_ecpointformatlist_length = os.length - 1;
+                       memcpy(ret->tlsext_ecpointformatlist, (unsigned char *) os.data + 1, os.length - 1);
+                       }
+               OPENSSL_free(os.data);
+               os.data = NULL;
+               os.length = 0;
+               }
+       else
+               {
+               ret->tlsext_ecpointformatlist=NULL;
+               ret->tlsext_ecpointformatlist_length=0;
+               }
+
+#endif /* OPENSSL_NO_EC */
 #endif /* OPENSSL_NO_TLSEXT */
 
 #ifndef OPENSSL_NO_PSK
        os.length=0;
        os.data=NULL;
-       M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,6);
+       M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,8);
        if (os.data)
                {
                ret->psk_identity_hint = BUF_strndup(os.data, os.length);
@@ -502,7 +558,7 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
 
        os.length=0;
        os.data=NULL;
-       M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,7);
+       M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,9);
        if (os.data)
                {
                ret->psk_identity = BUF_strndup(os.data, os.length);
index 67a1d4f..ebf1dd0 100644 (file)
@@ -241,7 +241,10 @@ static ERR_STRING_DATA SSL_str_functs[]=
 {ERR_FUNC(SSL_F_SSL_VERIFY_CERT_CHAIN),        "SSL_VERIFY_CERT_CHAIN"},
 {ERR_FUNC(SSL_F_SSL_WRITE),    "SSL_write"},
 {ERR_FUNC(SSL_F_TLS1_CHANGE_CIPHER_STATE),     "TLS1_CHANGE_CIPHER_STATE"},
+{ERR_FUNC(SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT),        "TLS1_CHECK_SERVERHELLO_TLSEXT"},
 {ERR_FUNC(SSL_F_TLS1_ENC),     "TLS1_ENC"},
+{ERR_FUNC(SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT),      "TLS1_PREPARE_CLIENTHELLO_TLSEXT"},
+{ERR_FUNC(SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT),      "TLS1_PREPARE_SERVERHELLO_TLSEXT"},
 {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
 {ERR_FUNC(SSL_F_WRITE_PENDING),        "WRITE_PENDING"},
 {0,NULL}
@@ -295,7 +298,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {ERR_REASON(SSL_R_CIPHER_CODE_WRONG_LENGTH),"cipher code wrong length"},
 {ERR_REASON(SSL_R_CIPHER_OR_HASH_UNAVAILABLE),"cipher or hash unavailable"},
 {ERR_REASON(SSL_R_CIPHER_TABLE_SRC_ERROR),"cipher table src error"},
-{ERR_REASON(SSL_R_CLIENTHELLO_TLS_EXT)   ,"clienthello tls ext"},
+{ERR_REASON(SSL_R_CLIENTHELLO_TLSEXT)    ,"clienthello tlsext"},
 {ERR_REASON(SSL_R_COMPRESSED_LENGTH_TOO_LONG),"compressed length too long"},
 {ERR_REASON(SSL_R_COMPRESSION_FAILURE)   ,"compression failure"},
 {ERR_REASON(SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE),"compression id not within private range"},
@@ -380,7 +383,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {ERR_REASON(SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED),"old session cipher not returned"},
 {ERR_REASON(SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE),"only tls allowed in fips mode"},
 {ERR_REASON(SSL_R_PACKET_LENGTH_TOO_LONG),"packet length too long"},
-{ERR_REASON(SSL_R_PARSE_TLS_EXT)         ,"parse tls ext"},
+{ERR_REASON(SSL_R_PARSE_TLSEXT)          ,"parse tlsext"},
 {ERR_REASON(SSL_R_PATH_TOO_LONG)         ,"path too long"},
 {ERR_REASON(SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE),"peer did not return a certificate"},
 {ERR_REASON(SSL_R_PEER_ERROR)            ,"peer error"},
@@ -407,12 +410,13 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {ERR_REASON(SSL_R_REUSE_CERT_LENGTH_NOT_ZERO),"reuse cert length not zero"},
 {ERR_REASON(SSL_R_REUSE_CERT_TYPE_NOT_ZERO),"reuse cert type not zero"},
 {ERR_REASON(SSL_R_REUSE_CIPHER_LIST_NOT_ZERO),"reuse cipher list not zero"},
-{ERR_REASON(SSL_R_SERVERHELLO_TLS_EXT)   ,"serverhello tls ext"},
+{ERR_REASON(SSL_R_SERVERHELLO_TLSEXT)    ,"serverhello tlsext"},
 {ERR_REASON(SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED),"session id context uninitialized"},
 {ERR_REASON(SSL_R_SHORT_READ)            ,"short read"},
 {ERR_REASON(SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE),"signature for non signing certificate"},
 {ERR_REASON(SSL_R_SSL23_DOING_SESSION_ID_REUSE),"ssl23 doing session id reuse"},
 {ERR_REASON(SSL_R_SSL2_CONNECTION_ID_TOO_LONG),"ssl2 connection id too long"},
+{ERR_REASON(SSL_R_SSL3_EXT_INVALID_ECPOINTFORMAT),"ssl3 ext invalid ecpointformat"},
 {ERR_REASON(SSL_R_SSL3_EXT_INVALID_SERVERNAME),"ssl3 ext invalid servername"},
 {ERR_REASON(SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE),"ssl3 ext invalid servername type"},
 {ERR_REASON(SSL_R_SSL3_SESSION_ID_TOO_LONG),"ssl3 session id too long"},
@@ -454,6 +458,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {ERR_REASON(SSL_R_TLSV1_UNRECOGNIZED_NAME),"tlsv1 unrecognized name"},
 {ERR_REASON(SSL_R_TLSV1_UNSUPPORTED_EXTENSION),"tlsv1 unsupported extension"},
 {ERR_REASON(SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER),"tls client cert req with anon cipher"},
+{ERR_REASON(SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST),"tls invalid ecpointformat list"},
 {ERR_REASON(SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST),"tls peer did not respond with certificate list"},
 {ERR_REASON(SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG),"tls rsa encrypted value length is wrong"},
 {ERR_REASON(SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER),"tried to use unsupported cipher"},
index 2beffcb..f0527f4 100644 (file)
@@ -975,6 +975,9 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
 unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit); 
 int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **data, unsigned char *d, int n, int *al);
 int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **data, unsigned char *d, int n, int *al);
-int ssl_check_tlsext(SSL *s, int is_server);
+int ssl_prepare_clienthello_tlsext(SSL *s);
+int ssl_prepare_serverhello_tlsext(SSL *s);
+int ssl_check_clienthello_tlsext(SSL *s);
+int ssl_check_serverhello_tlsext(SSL *s);
 #endif
 #endif
index a4a3a4b..9372a4e 100644 (file)
@@ -203,6 +203,10 @@ SSL_SESSION *SSL_SESSION_new(void)
        ss->compress_meth=0;
 #ifndef OPENSSL_NO_TLSEXT
        ss->tlsext_hostname = NULL; 
+#ifndef OPENSSL_NO_EC
+       ss->tlsext_ecpointformatlist_length = 0;
+       ss->tlsext_ecpointformatlist = NULL;
+#endif
 #endif
        CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data);
 #ifndef OPENSSL_NO_PSK
@@ -352,6 +356,19 @@ int ssl_get_new_session(SSL *s, int session)
                                return 0;
                                }
                        }
+#ifndef OPENSSL_NO_EC
+               if (s->tlsext_ecpointformatlist)
+                       {
+                       if ((ss->tlsext_ecpointformatlist = OPENSSL_malloc(s->tlsext_ecpointformatlist_length)) == NULL)
+                               {
+                               SSLerr(SSL_F_SSL_GET_NEW_SESSION, ERR_R_MALLOC_FAILURE);
+                               SSL_SESSION_free(ss);
+                               return 0;
+                               }
+                       ss->tlsext_ecpointformatlist_length = s->tlsext_ecpointformatlist_length;
+                       memcpy(ss->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
+                       }
+#endif
 #endif
                }
        else
@@ -644,6 +661,10 @@ void SSL_SESSION_free(SSL_SESSION *ss)
        if (ss->ciphers != NULL) sk_SSL_CIPHER_free(ss->ciphers);
 #ifndef OPENSSL_NO_TLSEXT
        if (ss->tlsext_hostname != NULL) OPENSSL_free(ss->tlsext_hostname);
+#ifndef OPENSSL_NO_EC
+       ss->tlsext_ecpointformatlist_length = 0;
+       if (ss->tlsext_ecpointformatlist != NULL) OPENSSL_free(ss->tlsext_ecpointformatlist);
+#endif /* OPENSSL_NO_EC */
 #endif
 #ifndef OPENSSL_NO_PSK
        if (ss->psk_identity_hint != NULL)
index d591daa..7f42cee 100644 (file)
@@ -181,6 +181,22 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                memcpy(ret, s->tlsext_hostname, size_str);
                ret+=size_str;
                }
+#ifndef OPENSSL_NO_EC
+       if (s->tlsext_ecpointformatlist != NULL)
+               {
+               /* Add TLS extension ECPointFormats to the ClientHello message */
+               long lenmax; 
+
+               if ((lenmax = limit - p - 5) < 0) return NULL; 
+               if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL;
+               
+               s2n(TLSEXT_TYPE_ec_point_formats,ret);
+               s2n(s->tlsext_ecpointformatlist_length + 1,ret);
+               *(ret++) = (unsigned char) s->tlsext_ecpointformatlist_length;
+               memcpy(ret, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
+               ret+=s->tlsext_ecpointformatlist_length;
+               }
+#endif /* OPENSSL_NO_EC */
 
        if ((extdatalen = ret-p-2)== 0) 
                return p;
@@ -204,6 +220,22 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
                s2n(TLSEXT_TYPE_server_name,ret);
                s2n(0,ret);
                }
+#ifndef OPENSSL_NO_EC
+       if (s->tlsext_ecpointformatlist != NULL)
+               {
+               /* Add TLS extension ECPointFormats to the ServerHello message */
+               long lenmax; 
+
+               if ((lenmax = limit - p - 5) < 0) return NULL; 
+               if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL;
+               
+               s2n(TLSEXT_TYPE_ec_point_formats,ret);
+               s2n(s->tlsext_ecpointformatlist_length + 1,ret);
+               *(ret++) = (unsigned char) s->tlsext_ecpointformatlist_length;
+               memcpy(ret, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
+               ret+=s->tlsext_ecpointformatlist_length;
+               }
+#endif /* OPENSSL_NO_EC */
        
        if ((extdatalen = ret-p-2)== 0) 
                return p;
@@ -314,8 +346,37 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                                }
                        }
 
+#ifndef OPENSSL_NO_EC
+               else if (type == TLSEXT_TYPE_ec_point_formats)
+                       {
+                       unsigned char *sdata = data;
+                       int ecpointformatlist_length = *(sdata++);
+                       int i;
+
+                       if (ecpointformatlist_length != size - 1)
+                               {
+                               *al = TLS1_AD_DECODE_ERROR;
+                               return 0;
+                               }
+                       s->session->tlsext_ecpointformatlist_length = 0;
+                       if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(ecpointformatlist_length)) == NULL)
+                               {
+                               *al = TLS1_AD_INTERNAL_ERROR;
+                               return 0;
+                               }
+                       s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length;
+                       memcpy(s->session->tlsext_ecpointformatlist, sdata, ecpointformatlist_length);
+#if 0
+                       fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_ecpointformatlist (length=%i) ", s->session->tlsext_ecpointformatlist_length);
+                       sdata = s->session->tlsext_ecpointformatlist;
+                       for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
+                               fprintf(stderr,"%i ",*(sdata++));
+                       fprintf(stderr,"\n");
+#endif
+                       }
                data+=size;             
                }
+#endif /* OPENSSL_NO_EC */
 
        *p = data;
        return 1;
@@ -329,6 +390,9 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
        unsigned char *data = *p;
 
        int tlsext_servername = 0;
+#ifndef OPENSSL_NO_EC
+       int tlsext_ecpointformats = 0;
+#endif /* OPENSSL_NO_EC */
 
        if (data >= (d+n-2))
                return 1;
@@ -353,8 +417,38 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                        tlsext_servername = 1;   
                        }
 
+#ifndef OPENSSL_NO_EC
+               else if (type == TLSEXT_TYPE_ec_point_formats)
+                       {
+                       unsigned char *sdata = data;
+                       int ecpointformatlist_length = *(sdata++);
+                       int i;
+
+                       if (ecpointformatlist_length != size - 1)
+                               {
+                               *al = TLS1_AD_DECODE_ERROR;
+                               return 0;
+                               }
+                       s->session->tlsext_ecpointformatlist_length = 0;
+                       if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(ecpointformatlist_length)) == NULL)
+                               {
+                               *al = TLS1_AD_INTERNAL_ERROR;
+                               return 0;
+                               }
+                       s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length;
+                       memcpy(s->session->tlsext_ecpointformatlist, sdata, ecpointformatlist_length);
+#if 0
+                       fprintf(stderr,"ssl_parse_serverhello_tlsext s->session->tlsext_ecpointformatlist ");
+                       sdata = s->session->tlsext_ecpointformatlist;
+                       for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
+                               fprintf(stderr,"%i ",*(sdata++));
+                       fprintf(stderr,"\n");
+#endif
+                       }
+
                data+=size;             
                }
+#endif /* OPENSSL_NO_EC */
 
        if (data != d+n)
                {
@@ -383,16 +477,168 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                        }
                }
 
+#ifndef OPENSSL_NO_EC
+       if (!s->hit && tlsext_ecpointformats == 1)
+               {
+               if (s->tlsext_ecpointformatlist)
+                       {
+                       if (s->session->tlsext_ecpointformatlist == NULL)
+                               {
+                               s->session->tlsext_ecpointformatlist_length = s->tlsext_ecpointformatlist_length;
+                               if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(s->tlsext_ecpointformatlist_length)) == NULL)
+                                       {
+                                       *al = TLS1_AD_INTERNAL_ERROR;
+                                       return 0;
+                                       }
+                               memcpy(s->session->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
+                               }
+                       else 
+                               {
+                               *al = SSL_AD_DECODE_ERROR;
+                               return 0;
+                               }
+                       }
+               }
+#endif /* OPENSSL_NO_EC */
+
        *p = data;
        return 1;
 }
 
-int ssl_check_tlsext(SSL *s, int is_server)
+int ssl_prepare_clienthello_tlsext(SSL *s)
+       {
+#ifndef OPENSSL_NO_EC
+       /* If we are client and using an elliptic curve cryptography cipher suite, send the point formats we 
+        * support (namely, only uncompressed points).
+        */
+       int using_ecc = 0;
+       int i;
+       int algs;
+       STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s);
+       for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++)
+               {
+               algs = (sk_SSL_CIPHER_value(cipher_stack, i))->algorithms;
+               if ((algs & SSL_kECDH) || (algs & SSL_kECDHE) || (algs & SSL_aECDSA)) 
+                       {
+                       using_ecc = 1;
+                       break;
+                       }
+
+               }
+       using_ecc = using_ecc && (s->version == TLS1_VERSION);
+       if (using_ecc)
+               {
+               if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(1)) == NULL)
+                       {
+                       SSLerr(SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
+                       return -1;
+                       }
+               s->tlsext_ecpointformatlist_length = 1;
+               *s->tlsext_ecpointformatlist = TLSEXT_ECPOINTFORMAT_uncompressed;
+               }
+#endif /* OPENSSL_NO_EC */
+       return 1;
+}
+
+int ssl_prepare_serverhello_tlsext(SSL *s)
+       {
+#ifndef OPENSSL_NO_EC
+       /* If we are server and using an ECC cipher suite, send the point formats we support (namely, only
+        * uncompressed points) if the client sent us an ECPointsFormat extension.
+        */
+       int i;
+       int algs = s->s3->tmp.new_cipher->algorithms;
+       int using_ecc = (algs & SSL_kECDH) || (algs & SSL_kECDHE) || (algs & SSL_aECDSA);
+       using_ecc = using_ecc && (s->session->tlsext_ecpointformatlist != NULL);
+
+       if (using_ecc)
+               {
+               if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(1)) == NULL)
+                       {
+                       SSLerr(SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
+                       return -1;
+                       }
+               s->tlsext_ecpointformatlist_length = 1;
+               *s->tlsext_ecpointformatlist = TLSEXT_ECPOINTFORMAT_uncompressed;
+               }
+#endif /* OPENSSL_NO_EC */
+       return 1;
+}
+
+int ssl_check_clienthello_tlsext(SSL *s)
        {
        int ret=SSL_TLSEXT_ERR_NOACK;
+       int al = SSL_AD_UNRECOGNIZED_NAME;
+
+#ifndef OPENSSL_NO_EC
+       /* If we are server and using an elliptic curve cyrptography cipher suite, then we don't
+        * need to check EC point formats since all clients must support uncompressed and it's the
+        * only thing we support; we just need to copy the data in.  We probably ought to check it
+        * for validity, but we never use it.
+        */
+#endif
+
+       if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) 
+               ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg);
+       else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0)             
+               ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
+
+       switch (ret) {
+               case SSL_TLSEXT_ERR_ALERT_FATAL:
+                       ssl3_send_alert(s,SSL3_AL_FATAL,al); 
+                       return -1;
+
+               case SSL_TLSEXT_ERR_ALERT_WARNING:
+                       ssl3_send_alert(s,SSL3_AL_WARNING,al);
+                       return 1; 
+                                       
+               case SSL_TLSEXT_ERR_NOACK:
+                       s->servername_done=0;
+                       default:
+               return 1;
+       }
+}
 
+int ssl_check_serverhello_tlsext(SSL *s)
+       {
+       int ret=SSL_TLSEXT_ERR_NOACK;
        int al = SSL_AD_UNRECOGNIZED_NAME;
 
+#ifndef OPENSSL_NO_EC
+       /* If we are client and using an elliptic curve cryptography cipher suite, then server
+        * must return a an EC point formats lists containing uncompressed.
+        */
+       int algs = s->s3->tmp.new_cipher->algorithms;
+       if ((s->tlsext_ecpointformatlist != NULL) && (s->tlsext_ecpointformatlist_length > 0) && 
+           ((algs & SSL_kECDH) || (algs & SSL_kECDHE) || (algs & SSL_aECDSA))) 
+               {
+               /* we are using an ECC cipher */
+               int i;
+               unsigned char *list;
+               int found_uncompressed = 0;
+               if ((s->session->tlsext_ecpointformatlist == NULL) || (s->session->tlsext_ecpointformatlist_length <= 0))
+                       {
+                       SSLerr(SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT,SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST);
+                       return -1;
+                       }
+               list = s->session->tlsext_ecpointformatlist;
+               for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
+                       {
+                       if (*(list++) == TLSEXT_ECPOINTFORMAT_uncompressed)
+                               {
+                               found_uncompressed = 1;
+                               break;
+                               }
+                       }
+               if (!found_uncompressed)
+                       {
+                       SSLerr(SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT,SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST);
+                       return -1;
+                       }
+               }
+       ret = SSL_TLSEXT_ERR_OK;
+#endif /* OPENSSL_NO_EC */
+
        if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) 
                ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg);
        else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0)             
index 4a33278..d839e9b 100644 (file)
@@ -190,10 +190,18 @@ extern "C" {
 #define TLSEXT_TYPE_trusted_ca_keys            3
 #define TLSEXT_TYPE_truncated_hmac             4
 #define TLSEXT_TYPE_status_request             5
+#define TLSEXT_TYPE_elliptic_curves            10
+#define TLSEXT_TYPE_ec_point_formats           11
 
 /* NameType value from RFC 3546 */
 #define TLSEXT_NAMETYPE_host_name 0
 
+/* ECPointFormat values from draft-ietf-tls-ecc-12 */
+#define TLSEXT_ECPOINTFORMAT_first                     0
+#define TLSEXT_ECPOINTFORMAT_uncompressed              0
+#define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime 1
+#define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2 2
+#define TLSEXT_ECPOINTFORMAT_last                      2
 
 #ifndef OPENSSL_NO_TLSEXT
 
@@ -216,6 +224,10 @@ SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_CB,(void (*)(void))cb)
 #define SSL_CTX_set_tlsext_servername_arg(ctx, arg) \
 SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG,0, (void *)arg)
 
+#ifndef OPENSSL_NO_EC
+#define SSL_set_tlsext_ecpointformat(s,length,list) \
+SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_ECPOINTFORMATLIST,length,(unsigned char *)list)
+#endif /* OPENSSL_NO_EC */
 #endif
 
 /* PSK ciphersuites from 4279 */