X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=ssl%2Ft1_lib.c;h=24e6451aabe9729d6032340f10c6ef8dab78589f;hp=b248dab36171d8e01303149d8dfe5541720fbf6b;hb=07ef612968bfd5be09d27b7ff7268beaa58a762f;hpb=f1fd4544a3747682010ed89ac908713fe90b8304;ds=sidebyside diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index b248dab361..24e6451aab 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -181,6 +181,27 @@ 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; + if (s->tlsext_ecpointformatlist_length > 255) + { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + 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; @@ -193,21 +214,38 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha { int extdatalen=0; unsigned char *ret = p; - if (s->hit || s->servername_done == 2) - return p; - ret+=2; - if (s->servername_done == 1) - s->servername_done = 2; + ret+=2; if (ret>=limit) return NULL; /* this really never occurs, but ... */ - if (s->session->tlsext_hostname != NULL) + if (!s->hit && s->servername_done == 1 && s->session->tlsext_hostname != NULL) { if (limit - p - 4 < 0) return NULL; 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; + if (s->tlsext_ecpointformatlist_length > 255) + { + SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + 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; @@ -222,6 +260,10 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in unsigned short size; unsigned short len; unsigned char *data = *p; +#if 0 + fprintf(stderr,"ssl_parse_clienthello_tlsext %s\n",s->session->tlsext_hostname?s->session->tlsext_hostname:"NULL"); +#endif + s->servername_done = 0; if (data >= (d+n-2)) return 1; @@ -238,6 +280,29 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in if (data+size > (d+n)) return 1; +/* The servername extension is treated as follows: + + - Only the hostname type is supported with a maximum length of 255. + - The servername is rejected if too long or if it contains zeros, + in which case an fatal alert is generated. + - The servername field is maintained together with the session cache. + - When a session is resumed, the servername call back invoked in order + to allow the application to position itself to the right context. + - The servername is acknowledged if it is new for a session or when + it is identical to a previously used for the same session. + Applications can control the behaviour. They can at any time + set a 'desirable' servername for a new SSL object. This can be the + case for example with HTTPS when a Host: header field is received and + a renegotiation is requested. In this case, a possible servername + presented in the new client hello is only acknowledged if it matches + the value of the Host: field. + - Applications must use SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION + if they provide for changing an explicit servername context for the session, + i.e. when the session has been established with a servername extension. + - On session reconnect, the servername extension may be absent. + +*/ + if (type == TLSEXT_TYPE_server_name) { unsigned char *sdata = data; @@ -259,16 +324,29 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in case TLSEXT_NAMETYPE_host_name: if (s->session->tlsext_hostname == NULL) { - if (len > 255 || + if (len > TLSEXT_MAXLEN_host_name || ((s->session->tlsext_hostname = OPENSSL_malloc(len+1)) == NULL)) { *al = TLS1_AD_UNRECOGNIZED_NAME; return 0; } - memcpy(s->session->tlsext_hostname, sdata, len); - s->session->tlsext_hostname[len]='\0'; + s->session->tlsext_hostname[len]='\0'; + if (strlen(s->session->tlsext_hostname) != len) { + OPENSSL_free(s->session->tlsext_hostname); + *al = TLS1_AD_UNRECOGNIZED_NAME; + return 0; + } + s->servername_done = 1; + +#if 0 + fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_hostname %s\n",s->session->tlsext_hostname); +#endif } + else + s->servername_done = strlen(s->session->tlsext_hostname) == len + && strncmp(s->session->tlsext_hostname, (char *)sdata, len) == 0; + break; default: @@ -278,8 +356,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++); + + if (ecpointformatlist_length != size - 1) + { + *al = TLS1_AD_DECODE_ERROR; + return 0; + } + s->session->tlsext_ecpointformatlist_length = 0; + if (s->session->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->session->tlsext_ecpointformatlist); + 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; @@ -293,6 +400,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; @@ -317,8 +427,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++); + + if (ecpointformatlist_length != size - 1) + { + *al = TLS1_AD_DECODE_ERROR; + return 0; + } + s->session->tlsext_ecpointformatlist_length = 0; + if (s->session->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->session->tlsext_ecpointformatlist); + 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) { @@ -347,24 +487,192 @@ 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 != NULL) OPENSSL_free(s->session->tlsext_ecpointformatlist); + 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 *al) +int ssl_prepare_clienthello_tlsext(SSL *s) { - int ret; +#ifndef OPENSSL_NO_EC + /* If we are client and using an elliptic curve cryptography cipher suite, send the point formats we + * support. + */ + 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; + } - *al = SSL_AD_UNRECOGNIZED_NAME; - if (s->servername_done == 0 && (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0)) + } + using_ecc = using_ecc && (s->version == TLS1_VERSION); + if (using_ecc) { - ret = s->ctx->tlsext_servername_callback(s, al, s->ctx->tlsext_servername_arg); - if (ret <= 0) - return ret; + if (s->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->tlsext_ecpointformatlist); + if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(3)) == NULL) + { + SSLerr(SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE); + return -1; + } + s->tlsext_ecpointformatlist_length = 3; + s->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_uncompressed; + s->tlsext_ecpointformatlist[1] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime; + s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2; } - if (s->servername_done == 1) - s->servername_done = 2; - +#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 + * if the client sent us an ECPointsFormat extension. + */ + 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 != NULL) OPENSSL_free(s->tlsext_ecpointformatlist); + if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(3)) == NULL) + { + SSLerr(SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT,ERR_R_MALLOC_FAILURE); + return -1; + } + s->tlsext_ecpointformatlist_length = 3; + s->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_uncompressed; + s->tlsext_ecpointformatlist[1] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime; + s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2; + } +#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 = (unsigned char *)(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) + 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; } +} #endif