From 36ca4ba63d083da6f9d4598f18f17a8c32c8eca2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Bodo=20M=C3=B6ller?= Date: Sat, 11 Mar 2006 23:46:37 +0000 Subject: [PATCH] Implement the Supported Point Formats Extension for ECC ciphersuites Submitted by: Douglas Stebila --- CHANGES | 4 + ssl/s3_clnt.c | 11 ++- ssl/s3_lib.c | 24 +++++ ssl/s3_srvr.c | 11 ++- ssl/ssl.h | 20 +++- ssl/ssl_asn1.c | 70 ++++++++++++-- ssl/ssl_err.c | 11 ++- ssl/ssl_locl.h | 5 +- ssl/ssl_sess.c | 21 +++++ ssl/t1_lib.c | 248 ++++++++++++++++++++++++++++++++++++++++++++++++- ssl/tls1.h | 12 +++ 11 files changed, 416 insertions(+), 21 deletions(-) diff --git a/CHANGES b/CHANGES index ffe039bf5b..41aae270d4 100644 --- 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. diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index 237dfb61d9..a8f2b8f557 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -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; } } diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index aecf6d62a8..0537a16743 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -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; diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 8859540fa8..43ff0d86f4 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -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); diff --git a/ssl/ssl.h b/ssl/ssl.h index 33792ea8fe..4d26c70210 100644 --- 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 diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c index a8193a58da..4845499633 100644 --- a/ssl/ssl_asn1.c +++ b/ssl/ssl_asn1.c @@ -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); diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 67a1d4ff36..ebf1dd09fc 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -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"}, diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 2beffcb9e0..f0527f459a 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -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 diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c index a4a3a4be45..9372a4ed87 100644 --- a/ssl/ssl_sess.c +++ b/ssl/ssl_sess.c @@ -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) diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index d591daaff6..7f42cee22a 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -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) diff --git a/ssl/tls1.h b/ssl/tls1.h index 4a33278a74..d839e9bdda 100644 --- a/ssl/tls1.h +++ b/ssl/tls1.h @@ -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 */ -- 2.25.1