Index: openssl/ssl/t1_lib.c |
=================================================================== |
--- openssl/ssl/t1_lib.c (revision 105093) |
+++ openssl/ssl/t1_lib.c (working copy) |
@@ -55,6 +55,59 @@ |
* copied and put under another distribution licence |
* [including the GNU Public Licence.] |
*/ |
+/* ==================================================================== |
+ * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved. |
+ * |
+ * Redistribution and use in source and binary forms, with or without |
+ * modification, are permitted provided that the following conditions |
+ * are met: |
+ * |
+ * 1. Redistributions of source code must retain the above copyright |
+ * notice, this list of conditions and the following disclaimer. |
+ * |
+ * 2. Redistributions in binary form must reproduce the above copyright |
+ * notice, this list of conditions and the following disclaimer in |
+ * the documentation and/or other materials provided with the |
+ * distribution. |
+ * |
+ * 3. All advertising materials mentioning features or use of this |
+ * software must display the following acknowledgment: |
+ * "This product includes software developed by the OpenSSL Project |
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" |
+ * |
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to |
+ * endorse or promote products derived from this software without |
+ * prior written permission. For written permission, please contact |
+ * openssl-core@openssl.org. |
+ * |
+ * 5. Products derived from this software may not be called "OpenSSL" |
+ * nor may "OpenSSL" appear in their names without prior written |
+ * permission of the OpenSSL Project. |
+ * |
+ * 6. Redistributions of any form whatsoever must retain the following |
+ * acknowledgment: |
+ * "This product includes software developed by the OpenSSL Project |
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)" |
+ * |
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY |
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR |
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
+ * OF THE POSSIBILITY OF SUCH DAMAGE. |
+ * ==================================================================== |
+ * |
+ * This product includes cryptographic software written by Eric Young |
+ * (eay@cryptsoft.com). This product includes software written by Tim |
+ * Hudson (tjh@cryptsoft.com). |
+ * |
+ */ |
#include <stdio.h> |
#include <openssl/objects.h> |
@@ -62,7 +115,6 @@ |
#include <openssl/hmac.h> |
#include <openssl/ocsp.h> |
#include "ssl_locl.h" |
-#include "fnv1a64.h" |
const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT; |
@@ -93,11 +145,6 @@ |
return(60*60*2); |
} |
-IMPLEMENT_tls1_meth_func(tlsv1_base_method, |
- ssl_undefined_function, |
- ssl_undefined_function, |
- ssl_bad_method) |
- |
int tls1_new(SSL *s) |
{ |
if (!ssl3_new(s)) return(0); |
@@ -107,6 +154,12 @@ |
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); |
} |
@@ -116,17 +169,105 @@ |
s->version=TLS1_VERSION; |
} |
-#if 0 |
-long tls1_ctrl(SSL *s, int cmd, long larg, char *parg) |
+#ifndef OPENSSL_NO_EC |
+static int nid_list[] = |
{ |
- return(0); |
+ 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]; |
} |
-long tls1_callback_ctrl(SSL *s, int cmd, void *(*fp)()) |
+int tls1_ec_nid2curve_id(int nid) |
{ |
- return(0); |
+ /* 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 |
+#endif /* OPENSSL_NO_EC */ |
#ifndef OPENSSL_NO_TLSEXT |
unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit) |
@@ -158,7 +299,7 @@ |
*/ |
if ((lenmax = limit - ret - 9) < 0 |
- || (size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax) |
+ || (size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax) |
return NULL; |
/* extension type and length */ |
@@ -173,9 +314,8 @@ |
s2n(size_str,ret); |
memcpy(ret, s->tlsext_hostname, size_str); |
ret+=size_str; |
+ } |
- } |
- |
/* Add RI if renegotiating */ |
if (s->new_session) |
{ |
@@ -201,19 +341,81 @@ |
ret += el; |
} |
- |
+#ifndef OPENSSL_NO_EC |
+ if (s->tlsext_ecpointformatlist != NULL && |
+ s->version != DTLS1_VERSION) |
+ { |
+ /* Add TLS extension ECPointFormats to the ClientHello message */ |
+ long lenmax; |
+ |
+ if ((lenmax = limit - ret - 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; |
+ } |
+ if (s->tlsext_ellipticcurvelist != NULL && |
+ s->version != DTLS1_VERSION) |
+ { |
+ /* Add TLS extension EllipticCurves to the ClientHello message */ |
+ long lenmax; |
+ |
+ if ((lenmax = limit - ret - 6) < 0) return NULL; |
+ if (s->tlsext_ellipticcurvelist_length > (unsigned long)lenmax) return NULL; |
+ if (s->tlsext_ellipticcurvelist_length > 65532) |
+ { |
+ SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); |
+ return NULL; |
+ } |
+ |
+ s2n(TLSEXT_TYPE_elliptic_curves,ret); |
+ s2n(s->tlsext_ellipticcurvelist_length + 2, ret); |
+ |
+ /* NB: draft-ietf-tls-ecc-12.txt uses a one-byte prefix for |
+ * elliptic_curve_list, but the examples use two bytes. |
+ * http://www1.ietf.org/mail-archive/web/tls/current/msg00538.html |
+ * resolves this to two bytes. |
+ */ |
+ s2n(s->tlsext_ellipticcurvelist_length, ret); |
+ memcpy(ret, s->tlsext_ellipticcurvelist, s->tlsext_ellipticcurvelist_length); |
+ ret+=s->tlsext_ellipticcurvelist_length; |
+ } |
+#endif /* OPENSSL_NO_EC */ |
+ |
if (!(SSL_get_options(s) & SSL_OP_NO_TICKET)) |
{ |
int ticklen; |
if (!s->new_session && 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 - ret - 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) |
@@ -222,7 +424,27 @@ |
ret += ticklen; |
} |
} |
+ skip_ext: |
+#ifdef TLSEXT_TYPE_opaque_prf_input |
+ if (s->s3->client_opaque_prf_input != NULL && |
+ s->version != DTLS1_VERSION) |
+ { |
+ 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 && |
s->version != DTLS1_VERSION) |
{ |
@@ -272,7 +494,8 @@ |
i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret); |
} |
- if (s->ctx->next_proto_select_cb) |
+#ifndef OPENSSL_NO_NEXTPROTONEG |
+ if (s->ctx->next_proto_select_cb && !s->s3->tmp.finish_md_len) |
{ |
/* The client advertises an emtpy extension to indicate its |
* support for Next Protocol Negotiation */ |
@@ -281,6 +504,7 @@ |
s2n(TLSEXT_TYPE_next_proto_neg,ret); |
s2n(0,ret); |
} |
+#endif |
if ((extdatalen = ret-p-2)== 0) |
return p; |
@@ -293,7 +517,9 @@ |
{ |
int extdatalen=0; |
unsigned char *ret = p; |
- char next_proto_neg_seen; |
+#ifndef OPENSSL_NO_NEXTPROTONEG |
+ int next_proto_neg_seen; |
+#endif |
/* don't add extensions for SSLv3, unless doing secure renegotiation */ |
if (s->version == SSL3_VERSION && !s->s3->send_connection_binding) |
@@ -304,7 +530,7 @@ |
if (!s->hit && s->servername_done == 1 && s->session->tlsext_hostname != NULL) |
{ |
- if (limit - ret - 4 < 0) return NULL; |
+ if ((long)(limit - ret - 4) < 0) return NULL; |
s2n(TLSEXT_TYPE_server_name,ret); |
s2n(0,ret); |
@@ -333,11 +559,36 @@ |
ret += el; |
} |
- |
+ |
+#ifndef OPENSSL_NO_EC |
+ if (s->tlsext_ecpointformatlist != NULL && |
+ s->version != DTLS1_VERSION) |
+ { |
+ /* Add TLS extension ECPointFormats to the ServerHello message */ |
+ long lenmax; |
+ |
+ if ((lenmax = limit - ret - 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; |
+ |
+ } |
+ /* 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 - ret - 4 < 0) return NULL; |
+ if ((long)(limit - ret - 4) < 0) return NULL; |
s2n(TLSEXT_TYPE_session_ticket,ret); |
s2n(0,ret); |
} |
@@ -349,6 +600,40 @@ |
s2n(0,ret); |
} |
+#ifdef TLSEXT_TYPE_opaque_prf_input |
+ if (s->s3->server_opaque_prf_input != NULL && |
+ s->version != DTLS1_VERSION) |
+ { |
+ 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; |
+ |
+ } |
+ |
+#ifndef OPENSSL_NO_NEXTPROTONEG |
next_proto_neg_seen = s->s3->next_proto_neg_seen; |
s->s3->next_proto_neg_seen = 0; |
if (next_proto_neg_seen && s->ctx->next_protos_advertised_cb) |
@@ -368,22 +653,8 @@ |
s->s3->next_proto_neg_seen = 1; |
} |
} |
+#endif |
- if (s->s3->snap_start_ext_seen) |
- { |
- if ((long)(limit - ret - 14) < 0) return NULL; |
- s2n(TLSEXT_TYPE_snap_start,ret); |
- s2n(10,ret); /* extension length */ |
- memcpy(ret, s->ctx->snap_start_orbit, 8); |
- ret += 8; |
- /* This is the ciphersuite that we would pick in the event of a |
- * Snap Start handshake. (Maybe the server wants to do EDH |
- * unless the client is Snap Start capable). At the moment we |
- * don't have any logic to pick a different cipher suite so we |
- * repeat the choice from the ServerHello. */ |
- s2n(s->s3->tmp.new_cipher->id & 0xffff,ret); |
- } |
- |
if ((extdatalen = ret-p-2)== 0) |
return p; |
@@ -391,174 +662,6 @@ |
return ret; |
} |
- |
-static int ssl_hash_snap_start_client_hello(SSL* s, |
- const char* data, |
- unsigned len, |
- unsigned ext_len) |
- { |
- /* We walk the ClientHello from the beginning, writing |
- * adjusted lengths into |b| and hashing as we go. |
- * |
- * The resulting ClientHello is going to be shorter by the length of |
- * this extension, which is |ext_len + 4| (two bytes for the type and two for |
- * the length). */ |
- |
- const unsigned char *p; |
- unsigned remaining; |
- unsigned char b[3], *c; |
- unsigned long l; |
- |
- p = (unsigned char*) data; |
- remaining = len; |
- /* Handshake header: type */ |
- if (!remaining) |
- return 0; |
- ssl3_finish_mac(s, p, 1); |
- p++; |
- remaining--; |
- /* Handshake header: length */ |
- if (remaining < 3) |
- return 0; |
- n2l3(p, l); |
- l -= ext_len + 4; |
- c = b; |
- l2n3(l, c); |
- ssl3_finish_mac(s, b, 3); |
- remaining -= 3; |
- /* ClientHello: version and random */ |
- if (remaining < 34) |
- return 0; |
- ssl3_finish_mac(s, p, 34); |
- p += 34; |
- remaining -= 34; |
- /* ClientHello: session id length */ |
- if (!remaining) |
- return 0; |
- l = *p; |
- ssl3_finish_mac(s, p, 1); |
- p++; |
- remaining--; |
- /* ClientHello: session id */ |
- if (remaining < l) |
- return 0; |
- ssl3_finish_mac(s, p, l); |
- p += l; |
- remaining -= l; |
- /* ClientHello: cipher suites length */ |
- if (remaining < 2) |
- return 0; |
- ssl3_finish_mac(s, p, 2); |
- n2s(p, l); |
- remaining -= 2; |
- /* ClientHello: cipher suites */ |
- if (remaining < l) |
- return 0; |
- ssl3_finish_mac(s, p, l); |
- p += l; |
- remaining -= l; |
- /* ClientHello: compression methods length */ |
- if (!remaining) |
- return 0; |
- l = *p; |
- ssl3_finish_mac(s, p, 1); |
- p++; |
- remaining--; |
- /* ClientHello: compression methods */ |
- if (remaining < l) |
- return 0; |
- ssl3_finish_mac(s, p, l); |
- p += l; |
- remaining -= l; |
- /* ClientHello: extensions length (must exist given that we're already |
- * parsing the extensions from it */ |
- if (remaining < 2) |
- return 0; |
- n2s(p, l); |
- remaining -= 2; |
- if (l != remaining || l < ext_len + 4) |
- return 0; |
- l -= ext_len + 4; |
- c = b; |
- s2n(l, c); |
- ssl3_finish_mac(s, b, 2); |
- |
- while (remaining) |
- { |
- unsigned long extension_type, extension_len; |
- if (remaining < 4) |
- return 0; |
- n2s(p, extension_type); |
- n2s(p, extension_len); |
- remaining -= 4; |
- if (remaining < extension_len) |
- return 0; |
- if (extension_type != TLSEXT_TYPE_snap_start) |
- ssl3_finish_mac(s, p - 4, extension_len + 4); |
- p += extension_len; |
- remaining -= extension_len; |
- } |
- |
- return 1; |
- } |
- |
-static char ssl_parse_snap_start_tlsext(SSL *s, const unsigned char *data, unsigned short len) |
- { |
- ptrdiff_t extension_offset = data - (unsigned char *) s->init_buf->data; |
- |
- if (len > 0 && len < 36) |
- return 0; |
- s->s3->snap_start_ext_seen = 1; |
- if (len == 0) |
- return 1; |
- |
- fnv1a64_init((FNV1A64*) s->s3->response_hash); |
- |
- /* We need to make a copy of the ClientHello because we'll be hashing a |
- * modified version. However, if we enter recovery then we need to hash |
- * the unchanged message. |
- * |
- * We are adding 4 bytes to the length here because we're including the |
- * handshake header. */ |
- s->s3->snap_start_client_hello.left = s->init_num + 4; |
- s->s3->snap_start_client_hello.offset = 0; |
- s->s3->snap_start_client_hello.buf = OPENSSL_malloc(s->init_num + 4); |
- if (!s->s3->snap_start_client_hello.buf) |
- { |
- /* If we're out of memory then we pretend that we |
- * didn't see the extension. */ |
- s->s3->snap_start_ext_seen = 0; |
- return 1; |
- } |
- |
- memcpy(s->s3->snap_start_client_hello.buf, s->init_buf->data, s->init_num + 4); |
- memcpy(s->s3->server_random, s->s3->client_random, 4); /* time */ |
- memcpy(s->s3->server_random + 4, data, 28); /* orbit and random bytes */ |
- memcpy(s->s3->predicted_response_hash, data + 28, 8); |
- |
- /* Point snap_start_records to within the copy of the ClientHello */ |
- s->s3->snap_start_records.offset = 0; |
- s->s3->snap_start_records.left = len - 36; |
- s->s3->snap_start_records.buf = s->s3->snap_start_client_hello.buf + extension_offset + 36; |
- |
- /* Reset the handshake hash */ |
- ssl3_init_finished_mac(s); |
- |
- /* Need to hash the ClientHello as if the snap start extension wasn't |
- * included. */ |
- if (!ssl_hash_snap_start_client_hello( |
- s, |
- s->init_buf->data, |
- s->init_num + 4 /* four bytes of handshake header */, |
- len)) |
- { |
- return 0; |
- } |
- |
- s->s3->snap_start_requested = 1; |
- return 1; |
- } |
- |
int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al) |
{ |
unsigned short type; |
@@ -572,7 +675,6 @@ |
if (data >= (d+n-2)) |
goto ri_check; |
- |
n2s(data,len); |
if (data > (d+n-len)) |
@@ -585,7 +687,9 @@ |
if (data+size > (d+n)) |
goto ri_check; |
- |
+#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); |
@@ -647,14 +751,23 @@ |
switch (servname_type) |
{ |
case TLSEXT_NAMETYPE_host_name: |
- if (s->session->tlsext_hostname == NULL) |
+ if (!s->hit) |
{ |
- if (len > TLSEXT_MAXLEN_host_name || |
- ((s->session->tlsext_hostname = OPENSSL_malloc(len+1)) == NULL)) |
+ if(s->session->tlsext_hostname) |
{ |
+ *al = SSL_AD_DECODE_ERROR; |
+ return 0; |
+ } |
+ if (len > TLSEXT_MAXLEN_host_name) |
+ { |
*al = TLS1_AD_UNRECOGNIZED_NAME; |
return 0; |
} |
+ if ((s->session->tlsext_hostname = OPENSSL_malloc(len+1)) == NULL) |
+ { |
+ *al = TLS1_AD_INTERNAL_ERROR; |
+ return 0; |
+ } |
memcpy(s->session->tlsext_hostname, sdata, len); |
s->session->tlsext_hostname[len]='\0'; |
if (strlen(s->session->tlsext_hostname) != len) { |
@@ -667,7 +780,8 @@ |
} |
else |
- s->servername_done = strlen(s->session->tlsext_hostname) == len |
+ s->servername_done = s->session->tlsext_hostname |
+ && strlen(s->session->tlsext_hostname) == len |
&& strncmp(s->session->tlsext_hostname, (char *)sdata, len) == 0; |
break; |
@@ -685,6 +799,120 @@ |
} |
} |
+ |
+#ifndef OPENSSL_NO_EC |
+ else if (type == TLSEXT_TYPE_ec_point_formats && |
+ s->version != DTLS1_VERSION) |
+ { |
+ unsigned char *sdata = data; |
+ int ecpointformatlist_length = *(sdata++); |
+ |
+ if (ecpointformatlist_length != size - 1) |
+ { |
+ *al = TLS1_AD_DECODE_ERROR; |
+ return 0; |
+ } |
+ if (!s->hit) |
+ { |
+ if(s->session->tlsext_ecpointformatlist) |
+ { |
+ OPENSSL_free(s->session->tlsext_ecpointformatlist); |
+ s->session->tlsext_ecpointformatlist = NULL; |
+ } |
+ 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 |
+ } |
+ else if (type == TLSEXT_TYPE_elliptic_curves && |
+ s->version != DTLS1_VERSION) |
+ { |
+ unsigned char *sdata = data; |
+ int ellipticcurvelist_length = (*(sdata++) << 8); |
+ ellipticcurvelist_length += (*(sdata++)); |
+ |
+ if (ellipticcurvelist_length != size - 2) |
+ { |
+ *al = TLS1_AD_DECODE_ERROR; |
+ return 0; |
+ } |
+ if (!s->hit) |
+ { |
+ if(s->session->tlsext_ellipticcurvelist) |
+ { |
+ *al = TLS1_AD_DECODE_ERROR; |
+ return 0; |
+ } |
+ s->session->tlsext_ellipticcurvelist_length = 0; |
+ if ((s->session->tlsext_ellipticcurvelist = OPENSSL_malloc(ellipticcurvelist_length)) == NULL) |
+ { |
+ *al = TLS1_AD_INTERNAL_ERROR; |
+ return 0; |
+ } |
+ s->session->tlsext_ellipticcurvelist_length = ellipticcurvelist_length; |
+ memcpy(s->session->tlsext_ellipticcurvelist, sdata, ellipticcurvelist_length); |
+ } |
+#if 0 |
+ fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_ellipticcurvelist (length=%i) ", s->session->tlsext_ellipticcurvelist_length); |
+ sdata = s->session->tlsext_ellipticcurvelist; |
+ for (i = 0; i < s->session->tlsext_ellipticcurvelist_length; i++) |
+ fprintf(stderr,"%i ",*(sdata++)); |
+ fprintf(stderr,"\n"); |
+#endif |
+ } |
+#endif /* OPENSSL_NO_EC */ |
+#ifdef TLSEXT_TYPE_opaque_prf_input |
+ else if (type == TLSEXT_TYPE_opaque_prf_input && |
+ s->version != DTLS1_VERSION) |
+ { |
+ 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_renegotiate) |
{ |
if(!ssl_parse_clienthello_renegotiate_ext(s, data, size, al)) |
@@ -726,6 +954,7 @@ |
} |
n2s(data, idsize); |
dsize -= 2 + idsize; |
+ size -= 2 + idsize; |
if (dsize < 0) |
{ |
*al = SSL_AD_DECODE_ERROR; |
@@ -764,9 +993,14 @@ |
} |
/* Read in request_extensions */ |
+ if (size < 2) |
+ { |
+ *al = SSL_AD_DECODE_ERROR; |
+ return 0; |
+ } |
n2s(data,dsize); |
size -= 2; |
- if (dsize > size) |
+ if (dsize != size) |
{ |
*al = SSL_AD_DECODE_ERROR; |
return 0; |
@@ -774,6 +1008,12 @@ |
sdata = data; |
if (dsize > 0) |
{ |
+ if (s->tlsext_ocsp_exts) |
+ { |
+ sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts, |
+ X509_EXTENSION_free); |
+ } |
+ |
s->tlsext_ocsp_exts = |
d2i_X509_EXTENSIONS(NULL, |
&sdata, dsize); |
@@ -791,10 +1031,12 @@ |
else |
s->tlsext_status_type = -1; |
} |
- else if (type == TLSEXT_TYPE_next_proto_neg) |
+#ifndef OPENSSL_NO_NEXTPROTONEG |
+ else if (type == TLSEXT_TYPE_next_proto_neg && |
+ s->s3->tmp.finish_md_len == 0) |
{ |
/* We shouldn't accept this extension on a |
- * renegotiation, but we currently do. |
+ * renegotiation. |
* |
* s->new_session will be set on renegotiation, but we |
* probably shouldn't rely that it couldn't be set on |
@@ -810,17 +1052,12 @@ |
* Finished message could have been computed.) */ |
s->s3->next_proto_neg_seen = 1; |
} |
+#endif |
- else if (type == TLSEXT_TYPE_snap_start && s->ctx->snap_start_orbit_valid) |
- { |
- if (ssl_parse_snap_start_tlsext(s, data, size) == 0) |
- return 0; |
- } |
- |
/* session ticket processed earlier */ |
- |
- data+=size; |
+ data+=size; |
} |
+ |
*p = data; |
ri_check: |
@@ -839,10 +1076,11 @@ |
return 1; |
} |
+#ifndef OPENSSL_NO_NEXTPROTONEG |
/* ssl_next_proto_validate validates a Next Protocol Negotiation block. No |
* elements of zero length are allowed and the set of elements must exactly fill |
* the length of the block. */ |
-static char ssl_next_proto_validate(unsigned char *d, unsigned len) |
+static int ssl_next_proto_validate(unsigned char *d, unsigned len) |
{ |
unsigned int off = 0; |
@@ -856,12 +1094,13 @@ |
return off == len; |
} |
+#endif |
int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al) |
{ |
+ unsigned short length; |
unsigned short type; |
unsigned short size; |
- unsigned short len; |
unsigned char *data = *p; |
int tlsext_servername = 0; |
int renegotiate_seen = 0; |
@@ -869,7 +1108,12 @@ |
if (data >= (d+n-2)) |
goto ri_check; |
- n2s(data,len); |
+ n2s(data,length); |
+ if (data+length != d+n) |
+ { |
+ *al = SSL_AD_DECODE_ERROR; |
+ return 0; |
+ } |
while(data <= (d+n-4)) |
{ |
@@ -892,8 +1136,46 @@ |
} |
tlsext_servername = 1; |
} |
+ |
+#ifndef OPENSSL_NO_EC |
+ else if (type == TLSEXT_TYPE_ec_point_formats && |
+ s->version != DTLS1_VERSION) |
+ { |
+ 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 |
+ } |
+#endif /* OPENSSL_NO_EC */ |
+ |
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)) |
{ |
@@ -902,6 +1184,38 @@ |
} |
s->tlsext_ticket_expected = 1; |
} |
+#ifdef TLSEXT_TYPE_opaque_prf_input |
+ else if (type == TLSEXT_TYPE_opaque_prf_input && |
+ s->version != DTLS1_VERSION) |
+ { |
+ 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 && |
s->version != DTLS1_VERSION) |
{ |
@@ -916,6 +1230,7 @@ |
/* Set flag to expect CertificateStatus message */ |
s->tlsext_status_expected = 1; |
} |
+#ifndef OPENSSL_NO_NEXTPROTONEG |
else if (type == TLSEXT_TYPE_next_proto_neg) |
{ |
unsigned char *selected; |
@@ -947,6 +1262,7 @@ |
memcpy(s->next_proto_negotiated, selected, selected_len); |
s->next_proto_negotiated_len = selected_len; |
} |
+#endif |
else if (type == TLSEXT_TYPE_renegotiate) |
{ |
if(!ssl_parse_serverhello_renegotiate_ext(s, data, size, al)) |
@@ -1007,11 +1323,142 @@ |
return 1; |
} |
+ |
+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 |
+ * and elliptic curves we support. |
+ */ |
+ int using_ecc = 0; |
+ int i; |
+ unsigned char *j; |
+ unsigned long alg_k, alg_a; |
+ STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s); |
+ |
+ for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++) |
+ { |
+ SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i); |
+ |
+ alg_k = c->algorithm_mkey; |
+ alg_a = c->algorithm_auth; |
+ if ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe) || (alg_a & SSL_aECDSA))) |
+ { |
+ using_ecc = 1; |
+ break; |
+ } |
+ } |
+ using_ecc = using_ecc && (s->version == TLS1_VERSION); |
+ if (using_ecc) |
+ { |
+ if (s->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->tlsext_ecpointformatlist); |
+ if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(3)) == NULL) |
+ { |
+ SSLerr(SSL_F_SSL_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; |
+ |
+ /* we support all named elliptic curves in draft-ietf-tls-ecc-12 */ |
+ if (s->tlsext_ellipticcurvelist != NULL) OPENSSL_free(s->tlsext_ellipticcurvelist); |
+ s->tlsext_ellipticcurvelist_length = sizeof(nid_list)/sizeof(nid_list[0]) * 2; |
+ if ((s->tlsext_ellipticcurvelist = OPENSSL_malloc(s->tlsext_ellipticcurvelist_length)) == NULL) |
+ { |
+ s->tlsext_ellipticcurvelist_length = 0; |
+ SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE); |
+ return -1; |
+ } |
+ 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; |
+ } |
+ |
+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. Note that the server is not |
+ * supposed to send an EllipticCurves extension. |
+ */ |
+ |
+ unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey; |
+ unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth; |
+ int using_ecc = (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) || (alg_a & 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_SSL_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 |
+ /* The handling of the ECPointFormats extension is done elsewhere, namely in |
+ * ssl3_choose_cipher in s3_lib.c. |
+ */ |
+ /* The handling of the EllipticCurves extension is done elsewhere, namely in |
+ * ssl3_choose_cipher in s3_lib.c. |
+ */ |
+#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) |
@@ -1021,7 +1468,7 @@ |
* Note: this must be called after servername callbacks in case |
* the certificate has changed. |
*/ |
- if ((s->tlsext_status_type != -1) && s->ctx->tlsext_status_cb) |
+ 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); |
@@ -1047,7 +1494,65 @@ |
} |
else |
s->tlsext_status_expected = 0; |
- err: |
+ |
+#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: |
@@ -1070,16 +1575,72 @@ |
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 if server returns an EC point formats lists extension |
+ * it must contain uncompressed. |
+ */ |
+ unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey; |
+ unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth; |
+ if ((s->tlsext_ecpointformatlist != NULL) && (s->tlsext_ecpointformatlist_length > 0) && |
+ (s->session->tlsext_ecpointformatlist != NULL) && (s->session->tlsext_ecpointformatlist_length > 0) && |
+ ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA))) |
+ { |
+ /* we are using an ECC cipher */ |
+ size_t i; |
+ unsigned char *list; |
+ int found_uncompressed = 0; |
+ 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_SSL_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); |
+#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->tlsext_status_cb) |
+ && s->ctx && s->ctx->tlsext_status_cb) |
{ |
int r; |
/* Set resp to NULL, resplen to -1 so callback knows |
@@ -1174,6 +1735,11 @@ |
return 1; |
if (type == TLSEXT_TYPE_session_ticket) |
{ |
+ /* If tickets disabled indicate cache miss which will |
+ * trigger a full handshake |
+ */ |
+ if (SSL_get_options(s) & SSL_OP_NO_TICKET) |
+ return 1; |
/* If zero length note client will accept a ticket |
* and indicate cache miss to trigger full handshake |
*/ |
@@ -1182,6 +1748,15 @@ |
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); |
} |
@@ -1234,6 +1809,11 @@ |
* integrity checks on ticket. |
*/ |
mlen = HMAC_size(&hctx); |
+ if (mlen < 0) |
+ { |
+ EVP_CIPHER_CTX_cleanup(&ctx); |
+ return -1; |
+ } |
eticklen -= mlen; |
/* Check HMAC of encrypted ticket */ |
HMAC_Update(&hctx, etick, eticklen); |