X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=ssl%2Ft1_lib.c;h=4d6789264d381d7b16774d7014f19841ef2c112c;hp=8d9ed9828080f57a0284f32b15af1d921c5ec455;hb=07a9d1a2c2b735cbc327065000b545deb5e136cf;hpb=367eb1f125063b9e76b6eaaacd85705023d435b4 diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 8d9ed98280..4d6789264d 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -113,6 +113,7 @@ #include #include #include +#include #include "ssl_locl.h" const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT; @@ -153,6 +154,12 @@ int tls1_new(SSL *s) void tls1_free(SSL *s) { +#ifndef OPENSSL_NO_TLSEXT + if (s->tlsext_session_ticket) + { + OPENSSL_free(s->tlsext_session_ticket); + } +#endif /* OPENSSL_NO_TLSEXT */ ssl3_free(s); } @@ -162,6 +169,105 @@ void tls1_clear(SSL *s) s->version=TLS1_VERSION; } +#ifndef OPENSSL_NO_EC +static int nid_list[] = + { + NID_sect163k1, /* sect163k1 (1) */ + NID_sect163r1, /* sect163r1 (2) */ + NID_sect163r2, /* sect163r2 (3) */ + NID_sect193r1, /* sect193r1 (4) */ + NID_sect193r2, /* sect193r2 (5) */ + NID_sect233k1, /* sect233k1 (6) */ + NID_sect233r1, /* sect233r1 (7) */ + NID_sect239k1, /* sect239k1 (8) */ + NID_sect283k1, /* sect283k1 (9) */ + NID_sect283r1, /* sect283r1 (10) */ + NID_sect409k1, /* sect409k1 (11) */ + NID_sect409r1, /* sect409r1 (12) */ + NID_sect571k1, /* sect571k1 (13) */ + NID_sect571r1, /* sect571r1 (14) */ + NID_secp160k1, /* secp160k1 (15) */ + NID_secp160r1, /* secp160r1 (16) */ + NID_secp160r2, /* secp160r2 (17) */ + NID_secp192k1, /* secp192k1 (18) */ + NID_X9_62_prime192v1, /* secp192r1 (19) */ + NID_secp224k1, /* secp224k1 (20) */ + NID_secp224r1, /* secp224r1 (21) */ + NID_secp256k1, /* secp256k1 (22) */ + NID_X9_62_prime256v1, /* secp256r1 (23) */ + NID_secp384r1, /* secp384r1 (24) */ + NID_secp521r1 /* secp521r1 (25) */ + }; + +int tls1_ec_curve_id2nid(int curve_id) + { + /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */ + if ((curve_id < 1) || ((unsigned int)curve_id > + sizeof(nid_list)/sizeof(nid_list[0]))) + return 0; + return nid_list[curve_id-1]; + } + +int tls1_ec_nid2curve_id(int nid) + { + /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */ + switch (nid) + { + case NID_sect163k1: /* sect163k1 (1) */ + return 1; + case NID_sect163r1: /* sect163r1 (2) */ + return 2; + case NID_sect163r2: /* sect163r2 (3) */ + return 3; + case NID_sect193r1: /* sect193r1 (4) */ + return 4; + case NID_sect193r2: /* sect193r2 (5) */ + return 5; + case NID_sect233k1: /* sect233k1 (6) */ + return 6; + case NID_sect233r1: /* sect233r1 (7) */ + return 7; + case NID_sect239k1: /* sect239k1 (8) */ + return 8; + case NID_sect283k1: /* sect283k1 (9) */ + return 9; + case NID_sect283r1: /* sect283r1 (10) */ + return 10; + case NID_sect409k1: /* sect409k1 (11) */ + return 11; + case NID_sect409r1: /* sect409r1 (12) */ + return 12; + case NID_sect571k1: /* sect571k1 (13) */ + return 13; + case NID_sect571r1: /* sect571r1 (14) */ + return 14; + case NID_secp160k1: /* secp160k1 (15) */ + return 15; + case NID_secp160r1: /* secp160r1 (16) */ + return 16; + case NID_secp160r2: /* secp160r2 (17) */ + return 17; + case NID_secp192k1: /* secp192k1 (18) */ + return 18; + case NID_X9_62_prime192v1: /* secp192r1 (19) */ + return 19; + case NID_secp224k1: /* secp224k1 (20) */ + return 20; + case NID_secp224r1: /* secp224r1 (21) */ + return 21; + case NID_secp256k1: /* secp256k1 (22) */ + return 22; + case NID_X9_62_prime256v1: /* secp256r1 (23) */ + return 23; + case NID_secp384r1: /* secp384r1 (24) */ + return 24; + case NID_secp521r1: /* secp521r1 (25) */ + return 25; + default: + return 0; + } + } +#endif /* OPENSSL_NO_EC */ #ifndef OPENSSL_NO_TLSEXT unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit) @@ -169,6 +275,10 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha int extdatalen=0; unsigned char *ret = p; + /* don't add extensions for SSLv3 */ + if (s->client_version == SSL3_VERSION) + return p; + ret+=2; if (ret>=limit) return NULL; /* this really never occurs, but ... */ @@ -187,8 +297,8 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha + hostname length */ - if ((lenmax = limit - p - 9) < 0 - || (size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax) + if ((lenmax = limit - ret - 9) < 0 + || (size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax) return NULL; /* extension type and length */ @@ -203,15 +313,15 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha s2n(size_str,ret); 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 ((lenmax = limit - ret - 5) < 0) return NULL; if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL; if (s->tlsext_ecpointformatlist_length > 255) { @@ -230,7 +340,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha /* Add TLS extension EllipticCurves to the ClientHello message */ long lenmax; - if ((lenmax = limit - p - 6) < 0) return NULL; + if ((lenmax = limit - ret - 6) < 0) return NULL; if (s->tlsext_ellipticcurvelist_length > (unsigned long)lenmax) return NULL; if (s->tlsext_ellipticcurvelist_length > 65532) { @@ -257,13 +367,27 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha int ticklen; if (s->session && s->session->tlsext_tick) ticklen = s->session->tlsext_ticklen; + else if (s->session && s->tlsext_session_ticket && + s->tlsext_session_ticket->data) + { + ticklen = s->tlsext_session_ticket->length; + s->session->tlsext_tick = OPENSSL_malloc(ticklen); + if (!s->session->tlsext_tick) + return NULL; + memcpy(s->session->tlsext_tick, + s->tlsext_session_ticket->data, + ticklen); + s->session->tlsext_ticklen = ticklen; + } else ticklen = 0; + if (ticklen == 0 && s->tlsext_session_ticket && + s->tlsext_session_ticket->data == NULL) + goto skip_ext; /* Check for enough room 2 for extension type, 2 for len * rest for ticket */ - if (limit - p - 4 - ticklen < 0) - return NULL; + if ((long)(limit - ret - 4 - ticklen) < 0) return NULL; s2n(TLSEXT_TYPE_session_ticket,ret); s2n(ticklen,ret); if (ticklen) @@ -272,6 +396,73 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha ret += ticklen; } } + skip_ext: + +#ifdef TLSEXT_TYPE_opaque_prf_input + if (s->s3->client_opaque_prf_input != NULL) + { + size_t col = s->s3->client_opaque_prf_input_len; + + if ((long)(limit - ret - 6 - col < 0)) + return NULL; + if (col > 0xFFFD) /* can't happen */ + return NULL; + + s2n(TLSEXT_TYPE_opaque_prf_input, ret); + s2n(col + 2, ret); + s2n(col, ret); + memcpy(ret, s->s3->client_opaque_prf_input, col); + ret += col; + } +#endif + + if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) + { + int i; + long extlen, idlen, itmp; + OCSP_RESPID *id; + + idlen = 0; + for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++) + { + id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i); + itmp = i2d_OCSP_RESPID(id, NULL); + if (itmp <= 0) + return NULL; + idlen += itmp + 2; + } + + if (s->tlsext_ocsp_exts) + { + extlen = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL); + if (extlen < 0) + return NULL; + } + else + extlen = 0; + + if ((long)(limit - ret - 7 - extlen - idlen) < 0) return NULL; + s2n(TLSEXT_TYPE_status_request, ret); + if (extlen + idlen > 0xFFF0) + return NULL; + s2n(extlen + idlen + 5, ret); + *(ret++) = TLSEXT_STATUSTYPE_ocsp; + s2n(idlen, ret); + for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++) + { + /* save position of id len */ + unsigned char *q = ret; + id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i); + /* skip over id len */ + ret += 2; + itmp = i2d_OCSP_RESPID(id, &ret); + /* write id len */ + s2n(itmp, q); + } + s2n(extlen, ret); + if (extlen > 0) + i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret); + } if ((extdatalen = ret-p-2)== 0) return p; @@ -285,12 +476,16 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha int extdatalen=0; unsigned char *ret = p; + /* don't add extensions for SSLv3 */ + if (s->version == SSL3_VERSION) + return p; + ret+=2; if (ret>=limit) return NULL; /* this really never occurs, but ... */ if (!s->hit && s->servername_done == 1 && s->session->tlsext_hostname != NULL) { - if (limit - p - 4 < 0) return NULL; + if ((long)(limit - ret - 4) < 0) return NULL; s2n(TLSEXT_TYPE_server_name,ret); s2n(0,ret); @@ -301,7 +496,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha /* Add TLS extension ECPointFormats to the ServerHello message */ long lenmax; - if ((lenmax = limit - p - 5) < 0) return NULL; + if ((lenmax = limit - ret - 5) < 0) return NULL; if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL; if (s->tlsext_ecpointformatlist_length > 255) { @@ -318,15 +513,54 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha } /* Currently the server should not respond with a SupportedCurves extension */ #endif /* OPENSSL_NO_EC */ - + if (s->tlsext_ticket_expected && !(SSL_get_options(s) & SSL_OP_NO_TICKET)) { - if (limit - p - 4 < 0) return NULL; + if ((long)(limit - ret - 4) < 0) return NULL; s2n(TLSEXT_TYPE_session_ticket,ret); s2n(0,ret); } + + if (s->tlsext_status_expected) + { + if ((long)(limit - ret - 4) < 0) return NULL; + s2n(TLSEXT_TYPE_status_request,ret); + s2n(0,ret); + } + +#ifdef TLSEXT_TYPE_opaque_prf_input + if (s->s3->server_opaque_prf_input != NULL) + { + size_t sol = s->s3->server_opaque_prf_input_len; + if ((long)(limit - ret - 6 - sol) < 0) + return NULL; + if (sol > 0xFFFD) /* can't happen */ + return NULL; + + s2n(TLSEXT_TYPE_opaque_prf_input, ret); + s2n(sol + 2, ret); + s2n(sol, ret); + memcpy(ret, s->s3->server_opaque_prf_input, sol); + ret += sol; + } +#endif + if (((s->s3->tmp.new_cipher->id & 0xFFFF)==0x80 || (s->s3->tmp.new_cipher->id & 0xFFFF)==0x81) + && (SSL_get_options(s) & SSL_OP_CRYPTOPRO_TLSEXT_BUG)) + { const unsigned char cryptopro_ext[36] = { + 0xfd, 0xe8, /*65000*/ + 0x00, 0x20, /*32 bytes length*/ + 0x30, 0x1e, 0x30, 0x08, 0x06, 0x06, 0x2a, 0x85, + 0x03, 0x02, 0x02, 0x09, 0x30, 0x08, 0x06, 0x06, + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x16, 0x30, 0x08, + 0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x17}; + if (limit-ret<36) return NULL; + memcpy(ret,cryptopro_ext,36); + ret+=36; + + } + if ((extdatalen = ret-p-2)== 0) return p; @@ -341,6 +575,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in unsigned short len; unsigned char *data = *p; s->servername_done = 0; + s->tlsext_status_type = -1; if (data >= (d+n-2)) return 1; @@ -356,7 +591,9 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in if (data+size > (d+n)) return 1; - +#if 0 + fprintf(stderr,"Received extension type %d size %d\n",type,size); +#endif if (s->tlsext_debug_cb) s->tlsext_debug_cb(s, 0, type, data, size, s->tlsext_debug_arg); @@ -430,6 +667,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in s->session->tlsext_hostname[len]='\0'; if (strlen(s->session->tlsext_hostname) != len) { OPENSSL_free(s->session->tlsext_hostname); + s->session->tlsext_hostname = NULL; *al = TLS1_AD_UNRECOGNIZED_NAME; return 0; } @@ -513,6 +751,146 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in #endif } #endif /* OPENSSL_NO_EC */ +#ifdef TLSEXT_TYPE_opaque_prf_input + else if (type == TLSEXT_TYPE_opaque_prf_input) + { + unsigned char *sdata = data; + + if (size < 2) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + n2s(sdata, s->s3->client_opaque_prf_input_len); + if (s->s3->client_opaque_prf_input_len != size - 2) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */ + OPENSSL_free(s->s3->client_opaque_prf_input); + if (s->s3->client_opaque_prf_input_len == 0) + s->s3->client_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */ + else + s->s3->client_opaque_prf_input = BUF_memdup(sdata, s->s3->client_opaque_prf_input_len); + if (s->s3->client_opaque_prf_input == NULL) + { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + } +#endif + else if (type == TLSEXT_TYPE_session_ticket) + { + if (s->tls_session_ticket_ext_cb && + !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg)) + { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + } + else if (type == TLSEXT_TYPE_status_request + && s->ctx->tlsext_status_cb) + { + + if (size < 5) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + s->tlsext_status_type = *data++; + size--; + if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) + { + const unsigned char *sdata; + int dsize; + /* Read in responder_id_list */ + n2s(data,dsize); + size -= 2; + if (dsize > size ) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + while (dsize > 0) + { + OCSP_RESPID *id; + int idsize; + if (dsize < 4) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + n2s(data, idsize); + dsize -= 2 + idsize; + if (dsize < 0) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + sdata = data; + data += idsize; + id = d2i_OCSP_RESPID(NULL, + &sdata, idsize); + if (!id) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + if (data != sdata) + { + OCSP_RESPID_free(id); + *al = SSL_AD_DECODE_ERROR; + return 0; + } + if (!s->tlsext_ocsp_ids + && !(s->tlsext_ocsp_ids = + sk_OCSP_RESPID_new_null())) + { + OCSP_RESPID_free(id); + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + if (!sk_OCSP_RESPID_push( + s->tlsext_ocsp_ids, id)) + { + OCSP_RESPID_free(id); + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + } + + /* Read in request_extensions */ + n2s(data,dsize); + size -= 2; + if (dsize > size) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + sdata = data; + if (dsize > 0) + { + s->tlsext_ocsp_exts = + d2i_X509_EXTENSIONS(NULL, + &sdata, dsize); + if (!s->tlsext_ocsp_exts + || (data + dsize != sdata)) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + } + } + /* We don't know what to do with any other type + * so ignore it. + */ + else + s->tlsext_status_type = -1; + } + /* session ticket processed earlier */ data+=size; } @@ -589,6 +967,12 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in else if (type == TLSEXT_TYPE_session_ticket) { + if (s->tls_session_ticket_ext_cb && + !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg)) + { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } if ((SSL_get_options(s) & SSL_OP_NO_TICKET) || (size > 0)) { @@ -597,6 +981,51 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in } s->tlsext_ticket_expected = 1; } +#ifdef TLSEXT_TYPE_opaque_prf_input + else if (type == TLSEXT_TYPE_opaque_prf_input) + { + unsigned char *sdata = data; + + if (size < 2) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + n2s(sdata, s->s3->server_opaque_prf_input_len); + if (s->s3->server_opaque_prf_input_len != size - 2) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + if (s->s3->server_opaque_prf_input != NULL) /* shouldn't really happen */ + OPENSSL_free(s->s3->server_opaque_prf_input); + if (s->s3->server_opaque_prf_input_len == 0) + s->s3->server_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */ + else + s->s3->server_opaque_prf_input = BUF_memdup(sdata, s->s3->server_opaque_prf_input_len); + + if (s->s3->server_opaque_prf_input == NULL) + { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + } +#endif + else if (type == TLSEXT_TYPE_status_request) + { + /* MUST be empty and only sent if we've requested + * a status request message. + */ + if ((s->tlsext_status_type == -1) || (size > 0)) + { + *al = TLS1_AD_UNSUPPORTED_EXTENSION; + return 0; + } + /* Set flag to expect CertificateStatus message */ + s->tlsext_status_expected = 1; + } + data+=size; } @@ -679,10 +1108,46 @@ int ssl_prepare_clienthello_tlsext(SSL *s) SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE); return -1; } - for (i = 1, j = s->tlsext_ellipticcurvelist; i <= sizeof(nid_list)/sizeof(nid_list[0]); i++) + for (i = 1, j = s->tlsext_ellipticcurvelist; (unsigned int)i <= + sizeof(nid_list)/sizeof(nid_list[0]); i++) s2n(i,j); } #endif /* OPENSSL_NO_EC */ + +#ifdef TLSEXT_TYPE_opaque_prf_input + { + int r = 1; + + if (s->ctx->tlsext_opaque_prf_input_callback != 0) + { + r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, s->ctx->tlsext_opaque_prf_input_callback_arg); + if (!r) + return -1; + } + + if (s->tlsext_opaque_prf_input != NULL) + { + if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */ + OPENSSL_free(s->s3->client_opaque_prf_input); + + if (s->tlsext_opaque_prf_input_len == 0) + s->s3->client_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */ + else + s->s3->client_opaque_prf_input = BUF_memdup(s->tlsext_opaque_prf_input, s->tlsext_opaque_prf_input_len); + if (s->s3->client_opaque_prf_input == NULL) + { + SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE); + return -1; + } + s->s3->client_opaque_prf_input_len = s->tlsext_opaque_prf_input_len; + } + + if (r == 2) + /* at callback's request, insist on receiving an appropriate server opaque PRF input */ + s->s3->server_opaque_prf_input_len = s->tlsext_opaque_prf_input_len; + } +#endif + return 1; } @@ -713,6 +1178,7 @@ int ssl_prepare_serverhello_tlsext(SSL *s) s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2; } #endif /* OPENSSL_NO_EC */ + return 1; } @@ -735,6 +1201,95 @@ int ssl_check_clienthello_tlsext(SSL *s) 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); + /* If status request then ask callback what to do. + * Note: this must be called after servername callbacks in case + * the certificate has changed. + */ + if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb) + { + int r; + r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg); + switch (r) + { + /* We don't want to send a status request response */ + case SSL_TLSEXT_ERR_NOACK: + s->tlsext_status_expected = 0; + break; + /* status request response should be sent */ + case SSL_TLSEXT_ERR_OK: + if (s->tlsext_ocsp_resp) + s->tlsext_status_expected = 1; + else + s->tlsext_status_expected = 0; + break; + /* something bad happened */ + case SSL_TLSEXT_ERR_ALERT_FATAL: + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + al = SSL_AD_INTERNAL_ERROR; + goto err; + } + } + else + s->tlsext_status_expected = 0; + +#ifdef TLSEXT_TYPE_opaque_prf_input + { + /* This sort of belongs into ssl_prepare_serverhello_tlsext(), + * but we might be sending an alert in response to the client hello, + * so this has to happen here in ssl_check_clienthello_tlsext(). */ + + int r = 1; + + if (s->ctx->tlsext_opaque_prf_input_callback != 0) + { + r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, s->ctx->tlsext_opaque_prf_input_callback_arg); + if (!r) + { + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + al = SSL_AD_INTERNAL_ERROR; + goto err; + } + } + + if (s->s3->server_opaque_prf_input != NULL) /* shouldn't really happen */ + OPENSSL_free(s->s3->server_opaque_prf_input); + s->s3->server_opaque_prf_input = NULL; + + if (s->tlsext_opaque_prf_input != NULL) + { + if (s->s3->client_opaque_prf_input != NULL && + s->s3->client_opaque_prf_input_len == s->tlsext_opaque_prf_input_len) + { + /* can only use this extension if we have a server opaque PRF input + * of the same length as the client opaque PRF input! */ + + if (s->tlsext_opaque_prf_input_len == 0) + s->s3->server_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */ + else + s->s3->server_opaque_prf_input = BUF_memdup(s->tlsext_opaque_prf_input, s->tlsext_opaque_prf_input_len); + if (s->s3->server_opaque_prf_input == NULL) + { + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + al = SSL_AD_INTERNAL_ERROR; + goto err; + } + s->s3->server_opaque_prf_input_len = s->tlsext_opaque_prf_input_len; + } + } + + if (r == 2 && s->s3->server_opaque_prf_input == NULL) + { + /* The callback wants to enforce use of the extension, + * but we can't do that with the client opaque PRF input; + * abort the handshake. + */ + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + al = SSL_AD_HANDSHAKE_FAILURE; + } + } + +#endif + err: switch (ret) { case SSL_TLSEXT_ERR_ALERT_FATAL: @@ -798,6 +1353,58 @@ int ssl_check_serverhello_tlsext(SSL *s) 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); +#ifdef TLSEXT_TYPE_opaque_prf_input + if (s->s3->server_opaque_prf_input_len > 0) + { + /* This case may indicate that we, as a client, want to insist on using opaque PRF inputs. + * So first verify that we really have a value from the server too. */ + + if (s->s3->server_opaque_prf_input == NULL) + { + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + al = SSL_AD_HANDSHAKE_FAILURE; + } + + /* Anytime the server *has* sent an opaque PRF input, we need to check + * that we have a client opaque PRF input of the same size. */ + if (s->s3->client_opaque_prf_input == NULL || + s->s3->client_opaque_prf_input_len != s->s3->server_opaque_prf_input_len) + { + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + al = SSL_AD_ILLEGAL_PARAMETER; + } + } +#endif + + /* If we've requested certificate status and we wont get one + * tell the callback + */ + if ((s->tlsext_status_type != -1) && !(s->tlsext_status_expected) + && s->ctx && s->ctx->tlsext_status_cb) + { + int r; + /* Set resp to NULL, resplen to -1 so callback knows + * there is no response. + */ + if (s->tlsext_ocsp_resp) + { + OPENSSL_free(s->tlsext_ocsp_resp); + s->tlsext_ocsp_resp = NULL; + } + s->tlsext_ocsp_resplen = -1; + r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg); + if (r == 0) + { + al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE; + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + } + if (r < 0) + { + al = SSL_AD_INTERNAL_ERROR; + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + } + } + switch (ret) { case SSL_TLSEXT_ERR_ALERT_FATAL: @@ -826,10 +1433,25 @@ int tls1_process_ticket(SSL *s, unsigned char *session_id, int len, /* Point after session ID in client hello */ const unsigned char *p = session_id + len; unsigned short i; + + /* If tickets disabled behave as if no ticket present + * to permit stateful resumption. + */ + if (SSL_get_options(s) & SSL_OP_NO_TICKET) + return 1; + if ((s->version <= SSL3_VERSION) || !limit) return 1; if (p >= limit) return -1; + /* Skip past DTLS cookie */ + if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER) + { + i = *(p++); + p+= i; + if (p >= limit) + return -1; + } /* Skip past cipher list */ n2s(p, i); p+= i; @@ -857,8 +1479,8 @@ int tls1_process_ticket(SSL *s, unsigned char *session_id, int len, * trigger a full handshake */ if (SSL_get_options(s) & SSL_OP_NO_TICKET) - return 0; - /* If zero length not client will accept a ticket + return 1; + /* If zero length note client will accept a ticket * and indicate cache miss to trigger full handshake */ if (size == 0) @@ -866,6 +1488,15 @@ int tls1_process_ticket(SSL *s, unsigned char *session_id, int len, s->tlsext_ticket_expected = 1; return 0; /* Cache miss */ } + if (s->tls_session_secret_cb) + { + /* Indicate cache miss here and instead of + * generating the session from ticket now, + * trigger abbreviated handshake based on + * external mechanism to calculate the master + * secret later. */ + return 0; + } return tls_decrypt_ticket(s, p, size, session_id, len, ret); } @@ -881,39 +1512,58 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen, SSL_SESSION *sess; unsigned char *sdec; const unsigned char *p; - int slen, mlen; + int slen, mlen, renew_ticket = 0; unsigned char tick_hmac[EVP_MAX_MD_SIZE]; HMAC_CTX hctx; EVP_CIPHER_CTX ctx; + /* Need at least keyname + iv + some encrypted data */ + if (eticklen < 48) + goto tickerr; + /* Initialize session ticket encryption and HMAC contexts */ + HMAC_CTX_init(&hctx); + EVP_CIPHER_CTX_init(&ctx); + if (s->ctx->tlsext_ticket_key_cb) + { + unsigned char *nctick = (unsigned char *)etick; + int rv = s->ctx->tlsext_ticket_key_cb(s, nctick, nctick + 16, + &ctx, &hctx, 0); + if (rv < 0) + return -1; + if (rv == 0) + goto tickerr; + if (rv == 2) + renew_ticket = 1; + } + else + { + /* Check key name matches */ + if (memcmp(etick, s->ctx->tlsext_tick_key_name, 16)) + goto tickerr; + HMAC_Init_ex(&hctx, s->ctx->tlsext_tick_hmac_key, 16, + tlsext_tick_md(), NULL); + EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, + s->ctx->tlsext_tick_aes_key, etick + 16); + } /* Attempt to process session ticket, first conduct sanity and * integrity checks on ticket. */ - mlen = EVP_MD_size(EVP_sha1()); + mlen = HMAC_size(&hctx); + if (mlen < 0) + { + EVP_CIPHER_CTX_cleanup(&ctx); + return -1; + } eticklen -= mlen; - /* Need at least keyname + iv + some encrypted data */ - if (eticklen < 48) - goto tickerr; - /* Check key name matches */ - if (memcmp(etick, s->ctx->tlsext_tick_key_name, 16)) - goto tickerr; /* Check HMAC of encrypted ticket */ - HMAC_CTX_init(&hctx); - HMAC_Init_ex(&hctx, s->ctx->tlsext_tick_hmac_key, 16, - EVP_sha1(), NULL); HMAC_Update(&hctx, etick, eticklen); HMAC_Final(&hctx, tick_hmac, NULL); HMAC_CTX_cleanup(&hctx); if (memcmp(tick_hmac, etick + eticklen, mlen)) goto tickerr; - /* Set p to start of IV */ - p = etick + 16; - EVP_CIPHER_CTX_init(&ctx); /* Attempt to decrypt session data */ - EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, - s->ctx->tlsext_tick_aes_key, p); /* Move p after IV to start of encrypted ticket, update length */ - p += 16; - eticklen -= 32; + p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx); + eticklen -= 16 + EVP_CIPHER_CTX_iv_length(&ctx); sdec = OPENSSL_malloc(eticklen); if (!sdec) { @@ -940,6 +1590,7 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen, memcpy(sess->session_id, sess_id, sesslen); sess->session_id_length = sesslen; *psess = sess; + s->tlsext_ticket_expected = renew_ticket; return 1; } /* If session decrypt failure indicate a cache miss and set state to @@ -951,100 +1602,3 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen, } #endif -#ifndef OPENSSL_NO_EC -static int nid_list[] = - { - NID_sect163k1, /* sect163k1 (1) */ - NID_sect163r1, /* sect163r1 (2) */ - NID_sect163r2, /* sect163r2 (3) */ - NID_sect193r1, /* sect193r1 (4) */ - NID_sect193r2, /* sect193r2 (5) */ - NID_sect233k1, /* sect233k1 (6) */ - NID_sect233r1, /* sect233r1 (7) */ - NID_sect239k1, /* sect239k1 (8) */ - NID_sect283k1, /* sect283k1 (9) */ - NID_sect283r1, /* sect283r1 (10) */ - NID_sect409k1, /* sect409k1 (11) */ - NID_sect409r1, /* sect409r1 (12) */ - NID_sect571k1, /* sect571k1 (13) */ - NID_sect571r1, /* sect571r1 (14) */ - NID_secp160k1, /* secp160k1 (15) */ - NID_secp160r1, /* secp160r1 (16) */ - NID_secp160r2, /* secp160r2 (17) */ - NID_secp192k1, /* secp192k1 (18) */ - NID_X9_62_prime192v1, /* secp192r1 (19) */ - NID_secp224k1, /* secp224k1 (20) */ - NID_secp224r1, /* secp224r1 (21) */ - NID_secp256k1, /* secp256k1 (22) */ - NID_X9_62_prime256v1, /* secp256r1 (23) */ - NID_secp384r1, /* secp384r1 (24) */ - NID_secp521r1 /* secp521r1 (25) */ - }; - -int tls1_ec_curve_id2nid(int curve_id) - { - /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */ - if ((curve_id < 1) || (curve_id > sizeof(nid_list)/sizeof(nid_list[0]))) return 0; - return nid_list[curve_id-1]; - } - -int tls1_ec_nid2curve_id(int nid) - { - /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */ - switch (nid) - { - case NID_sect163k1: /* sect163k1 (1) */ - return 1; - case NID_sect163r1: /* sect163r1 (2) */ - return 2; - case NID_sect163r2: /* sect163r2 (3) */ - return 3; - case NID_sect193r1: /* sect193r1 (4) */ - return 4; - case NID_sect193r2: /* sect193r2 (5) */ - return 5; - case NID_sect233k1: /* sect233k1 (6) */ - return 6; - case NID_sect233r1: /* sect233r1 (7) */ - return 7; - case NID_sect239k1: /* sect239k1 (8) */ - return 8; - case NID_sect283k1: /* sect283k1 (9) */ - return 9; - case NID_sect283r1: /* sect283r1 (10) */ - return 10; - case NID_sect409k1: /* sect409k1 (11) */ - return 11; - case NID_sect409r1: /* sect409r1 (12) */ - return 12; - case NID_sect571k1: /* sect571k1 (13) */ - return 13; - case NID_sect571r1: /* sect571r1 (14) */ - return 14; - case NID_secp160k1: /* secp160k1 (15) */ - return 15; - case NID_secp160r1: /* secp160r1 (16) */ - return 16; - case NID_secp160r2: /* secp160r2 (17) */ - return 17; - case NID_secp192k1: /* secp192k1 (18) */ - return 18; - case NID_X9_62_prime192v1: /* secp192r1 (19) */ - return 19; - case NID_secp224k1: /* secp224k1 (20) */ - return 20; - case NID_secp224r1: /* secp224r1 (21) */ - return 21; - case NID_secp256k1: /* secp256k1 (22) */ - return 22; - case NID_X9_62_prime256v1: /* secp256r1 (23) */ - return 23; - case NID_secp384r1: /* secp384r1 (24) */ - return 24; - case NID_secp521r1: /* secp521r1 (25) */ - return 25; - default: - return 0; - } - } -#endif /* OPENSSL_NO_EC */