diff -burN android-openssl.orig/include/openssl/ssl.h android-openssl/include/openssl/ssl.h --- android-openssl.orig/include/openssl/ssl.h 2014-05-05 16:45:02.685389339 +0200 +++ android-openssl/include/openssl/ssl.h 2014-05-05 16:46:32.513390565 +0200 @@ -544,6 +544,13 @@ #ifndef OPENSSL_NO_SRP char *srp_username; #endif + + /* original_handshake_hash contains the handshake hash (either + * SHA-1+MD5 or SHA-2, depending on TLS version) for the original, full + * handshake that created a session. This is used by Channel IDs during + * resumption. */ + unsigned char original_handshake_hash[EVP_MAX_MD_SIZE]; + unsigned int original_handshake_hash_len; }; #endif diff -burN android-openssl.orig/include/openssl/tls1.h android-openssl/include/openssl/tls1.h --- android-openssl.orig/include/openssl/tls1.h 2014-05-05 16:45:02.689389339 +0200 +++ android-openssl/include/openssl/tls1.h 2014-05-05 16:46:32.517390565 +0200 @@ -249,7 +249,7 @@ #endif /* This is not an IANA defined extension number */ -#define TLSEXT_TYPE_channel_id 30031 +#define TLSEXT_TYPE_channel_id 30032 /* NameType value from RFC 3546 */ #define TLSEXT_NAMETYPE_host_name 0 diff -burN android-openssl.orig/patches/new_channelid.patch android-openssl/patches/new_channelid.patch --- android-openssl.orig/patches/new_channelid.patch 1970-01-01 01:00:00.000000000 +0100 +++ android-openssl/patches/new_channelid.patch 2014-05-05 16:48:54.429392502 +0200 @@ -0,0 +1,273 @@ +diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h +index a3944f1..fe92ccf 100644 +--- a/include/openssl/ssl.h ++++ b/include/openssl/ssl.h +@@ -547,6 +547,13 @@ struct ssl_session_st + #ifndef OPENSSL_NO_SRP + char *srp_username; + #endif ++ ++ /* original_handshake_hash contains the handshake hash (either ++ * SHA-1+MD5 or SHA-2, depending on TLS version) for the original, full ++ * handshake that created a session. This is used by Channel IDs during ++ * resumption. */ ++ unsigned char original_handshake_hash[EVP_MAX_MD_SIZE]; ++ unsigned int original_handshake_hash_len; + }; + + #endif +diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h +index c4f69aa..5559486 100644 +--- a/include/openssl/tls1.h ++++ b/include/openssl/tls1.h +@@ -255,7 +255,7 @@ extern "C" { + #endif + + /* This is not an IANA defined extension number */ +-#define TLSEXT_TYPE_channel_id 30031 ++#define TLSEXT_TYPE_channel_id 30032 + + /* NameType value from RFC 3546 */ + #define TLSEXT_NAMETYPE_host_name 0 +diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c +index 640df80..d6154c5 100644 +--- a/ssl/s3_clnt.c ++++ b/ssl/s3_clnt.c +@@ -583,6 +583,18 @@ int ssl3_connect(SSL *s) + #endif + s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A; + } ++ if (s->s3->tlsext_channel_id_valid) ++ { ++ /* This is a non-resumption handshake. If it ++ * involves ChannelID, then record the ++ * handshake hashes at this point in the ++ * session so that any resumption of this ++ * session with ChannelID can sign those ++ * hashes. */ ++ ret = tls1_record_handshake_hashes_for_channel_id(s); ++ if (ret <= 0) ++ goto end; ++ } + } + s->init_num=0; + break; +diff --git a/ssl/ssl.h b/ssl/ssl.h +index a3944f1..fe92ccf 100644 +--- a/ssl/ssl.h ++++ b/ssl/ssl.h +@@ -547,6 +547,13 @@ struct ssl_session_st + #ifndef OPENSSL_NO_SRP + char *srp_username; + #endif ++ ++ /* original_handshake_hash contains the handshake hash (either ++ * SHA-1+MD5 or SHA-2, depending on TLS version) for the original, full ++ * handshake that created a session. This is used by Channel IDs during ++ * resumption. */ ++ unsigned char original_handshake_hash[EVP_MAX_MD_SIZE]; ++ unsigned int original_handshake_hash_len; + }; + + #endif +diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h +index 531a291..c975d31 100644 +--- a/ssl/ssl_locl.h ++++ b/ssl/ssl_locl.h +@@ -1102,6 +1102,7 @@ void ssl_free_wbio_buffer(SSL *s); + int tls1_change_cipher_state(SSL *s, int which); + int tls1_setup_key_block(SSL *s); + int tls1_enc(SSL *s, int snd); ++int tls1_handshake_digest(SSL *s, unsigned char *out, size_t out_len); + int tls1_final_finish_mac(SSL *s, + const char *str, int slen, unsigned char *p); + int tls1_cert_verify_mac(SSL *s, int md_nid, unsigned char *p); +@@ -1158,6 +1159,7 @@ int tls12_get_sigid(const EVP_PKEY *pk); + const EVP_MD *tls12_get_hash(unsigned char hash_alg); + + int tls1_channel_id_hash(EVP_MD_CTX *ctx, SSL *s); ++int tls1_record_handshake_hashes_for_channel_id(SSL *s); + #endif + + int ssl3_can_cutthrough(const SSL *s); +diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c +index 87b7021..d30ce61 100644 +--- a/ssl/t1_enc.c ++++ b/ssl/t1_enc.c +@@ -1147,53 +1147,79 @@ int tls1_cert_verify_mac(SSL *s, int md_nid, unsigned char *out) + return((int)ret); + } + ++/* tls1_handshake_digest calculates the current handshake hash and writes it to ++ * |out|, which has space for |out_len| bytes. It returns the number of bytes ++ * written or -1 in the event of an error. This function works on a copy of the ++ * underlying digests so can be called multiple times and prior to the final ++ * update etc. */ ++int tls1_handshake_digest(SSL *s, unsigned char *out, size_t out_len) ++ { ++ const EVP_MD *md; ++ EVP_MD_CTX ctx; ++ int i, err = 0, len = 0; ++ long mask; ++ ++ EVP_MD_CTX_init(&ctx); ++ ++ for (i = 0; ssl_get_handshake_digest(i, &mask, &md); i++) ++ { ++ int hash_size; ++ unsigned int digest_len; ++ EVP_MD_CTX *hdgst = s->s3->handshake_dgst[i]; ++ ++ if ((mask & ssl_get_algorithm2(s)) == 0) ++ continue; ++ ++ hash_size = EVP_MD_size(md); ++ if (!hdgst || hash_size < 0 || (size_t)hash_size > out_len) ++ { ++ err = 1; ++ break; ++ } ++ ++ if (!EVP_MD_CTX_copy_ex(&ctx, hdgst) || ++ !EVP_DigestFinal_ex(&ctx, out, &digest_len) || ++ digest_len != (unsigned int)hash_size) /* internal error */ ++ { ++ err = 1; ++ break; ++ } ++ out += digest_len; ++ out_len -= digest_len; ++ len += digest_len; ++ } ++ ++ EVP_MD_CTX_cleanup(&ctx); ++ ++ if (err != 0) ++ return -1; ++ return len; ++ } ++ + int tls1_final_finish_mac(SSL *s, + const char *str, int slen, unsigned char *out) + { +- unsigned int i; +- EVP_MD_CTX ctx; + unsigned char buf[2*EVP_MAX_MD_SIZE]; +- unsigned char *q,buf2[12]; +- int idx; +- long mask; ++ unsigned char buf2[12]; + int err=0; +- const EVP_MD *md; ++ int digests_len; + +- q=buf; +- +- if (s->s3->handshake_buffer) ++ if (s->s3->handshake_buffer) + if (!ssl3_digest_cached_records(s)) + return 0; + +- EVP_MD_CTX_init(&ctx); +- +- for (idx=0;ssl_get_handshake_digest(idx,&mask,&md);idx++) ++ digests_len = tls1_handshake_digest(s, buf, sizeof(buf)); ++ if (digests_len < 0) + { +- if (mask & ssl_get_algorithm2(s)) +- { +- int hashsize = EVP_MD_size(md); +- if (hashsize < 0 || hashsize > (int)(sizeof buf - (size_t)(q-buf))) +- { +- /* internal error: 'buf' is too small for this cipersuite! */ +- err = 1; +- } +- else +- { +- EVP_MD_CTX_copy_ex(&ctx,s->s3->handshake_dgst[idx]); +- EVP_DigestFinal_ex(&ctx,q,&i); +- if (i != (unsigned int)hashsize) /* can't really happen */ +- err = 1; +- q+=i; +- } +- } ++ err = 1; ++ digests_len = 0; + } +- ++ + if (!tls1_PRF(ssl_get_algorithm2(s), +- str,slen, buf,(int)(q-buf), NULL,0, NULL,0, NULL,0, ++ str,slen, buf, digests_len, NULL,0, NULL,0, NULL,0, + s->session->master_key,s->session->master_key_length, + out,buf2,sizeof buf2)) + err = 1; +- EVP_MD_CTX_cleanup(&ctx); + + if (err) + return 0; +diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c +index ea7fefa..d7ea9a5 100644 +--- a/ssl/t1_lib.c ++++ b/ssl/t1_lib.c +@@ -2684,6 +2684,17 @@ tls1_channel_id_hash(EVP_MD_CTX *md, SSL *s) + + EVP_DigestUpdate(md, kClientIDMagic, sizeof(kClientIDMagic)); + ++ if (s->hit) ++ { ++ static const char kResumptionMagic[] = "Resumption"; ++ EVP_DigestUpdate(md, kResumptionMagic, ++ sizeof(kResumptionMagic)); ++ if (s->session->original_handshake_hash_len == 0) ++ return 0; ++ EVP_DigestUpdate(md, s->session->original_handshake_hash, ++ s->session->original_handshake_hash_len); ++ } ++ + EVP_MD_CTX_init(&ctx); + for (i = 0; i < SSL_MAX_DIGEST; i++) + { +@@ -2698,3 +2709,29 @@ tls1_channel_id_hash(EVP_MD_CTX *md, SSL *s) + return 1; + } + #endif ++ ++/* tls1_record_handshake_hashes_for_channel_id records the current handshake ++ * hashes in |s->session| so that Channel ID resumptions can sign that data. */ ++int tls1_record_handshake_hashes_for_channel_id(SSL *s) ++ { ++ int digest_len; ++ /* This function should never be called for a resumed session because ++ * the handshake hashes that we wish to record are for the original, ++ * full handshake. */ ++ if (s->hit) ++ return -1; ++ /* It only makes sense to call this function if Channel IDs have been ++ * negotiated. */ ++ if (!s->s3->tlsext_channel_id_valid) ++ return -1; ++ ++ digest_len = tls1_handshake_digest( ++ s, s->session->original_handshake_hash, ++ sizeof(s->session->original_handshake_hash)); ++ if (digest_len < 0) ++ return -1; ++ ++ s->session->original_handshake_hash_len = digest_len; ++ ++ return 1; ++ } +diff --git a/ssl/tls1.h b/ssl/tls1.h +index c4f69aa..5559486 100644 +--- a/ssl/tls1.h ++++ b/ssl/tls1.h +@@ -255,7 +255,7 @@ extern "C" { + #endif + + /* This is not an IANA defined extension number */ +-#define TLSEXT_TYPE_channel_id 30031 ++#define TLSEXT_TYPE_channel_id 30032 + + /* NameType value from RFC 3546 */ + #define TLSEXT_NAMETYPE_host_name 0 diff -burN android-openssl.orig/ssl/s3_clnt.c android-openssl/ssl/s3_clnt.c --- android-openssl.orig/ssl/s3_clnt.c 2014-05-05 16:45:02.785389340 +0200 +++ android-openssl/ssl/s3_clnt.c 2014-05-05 16:46:32.525390565 +0200 @@ -583,6 +583,18 @@ #endif s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A; } + if (s->s3->tlsext_channel_id_valid) + { + /* This is a non-resumption handshake. If it + * involves ChannelID, then record the + * handshake hashes at this point in the + * session so that any resumption of this + * session with ChannelID can sign those + * hashes. */ + ret = tls1_record_handshake_hashes_for_channel_id(s); + if (ret <= 0) + goto end; + } } s->init_num=0; break; diff -burN android-openssl.orig/ssl/ssl.h android-openssl/ssl/ssl.h --- android-openssl.orig/ssl/ssl.h 2014-05-05 16:45:02.693389339 +0200 +++ android-openssl/ssl/ssl.h 2014-05-05 16:46:32.533390565 +0200 @@ -544,6 +544,13 @@ #ifndef OPENSSL_NO_SRP char *srp_username; #endif + + /* original_handshake_hash contains the handshake hash (either + * SHA-1+MD5 or SHA-2, depending on TLS version) for the original, full + * handshake that created a session. This is used by Channel IDs during + * resumption. */ + unsigned char original_handshake_hash[EVP_MAX_MD_SIZE]; + unsigned int original_handshake_hash_len; }; #endif diff -burN android-openssl.orig/ssl/ssl_locl.h android-openssl/ssl/ssl_locl.h --- android-openssl.orig/ssl/ssl_locl.h 2014-05-05 16:45:02.785389340 +0200 +++ android-openssl/ssl/ssl_locl.h 2014-05-05 16:46:32.541390565 +0200 @@ -1071,6 +1071,7 @@ int tls1_change_cipher_state(SSL *s, int which); int tls1_setup_key_block(SSL *s); int tls1_enc(SSL *s, int snd); +int tls1_handshake_digest(SSL *s, unsigned char *out, size_t out_len); int tls1_final_finish_mac(SSL *s, const char *str, int slen, unsigned char *p); int tls1_cert_verify_mac(SSL *s, int md_nid, unsigned char *p); @@ -1127,6 +1128,7 @@ const EVP_MD *tls12_get_hash(unsigned char hash_alg); int tls1_channel_id_hash(EVP_MD_CTX *ctx, SSL *s); +int tls1_record_handshake_hashes_for_channel_id(SSL *s); #endif int ssl3_can_cutthrough(const SSL *s); diff -burN android-openssl.orig/ssl/t1_enc.c android-openssl/ssl/t1_enc.c --- android-openssl.orig/ssl/t1_enc.c 2014-05-05 16:45:02.697389339 +0200 +++ android-openssl/ssl/t1_enc.c 2014-05-05 16:46:32.545390565 +0200 @@ -890,53 +890,79 @@ return((int)ret); } -int tls1_final_finish_mac(SSL *s, - const char *str, int slen, unsigned char *out) +/* tls1_handshake_digest calculates the current handshake hash and writes it to + * |out|, which has space for |out_len| bytes. It returns the number of bytes + * written or -1 in the event of an error. This function works on a copy of the + * underlying digests so can be called multiple times and prior to the final + * update etc. */ +int tls1_handshake_digest(SSL *s, unsigned char *out, size_t out_len) { - unsigned int i; + const EVP_MD *md; EVP_MD_CTX ctx; - unsigned char buf[2*EVP_MAX_MD_SIZE]; - unsigned char *q,buf2[12]; - int idx; + int i, err = 0, len = 0; long mask; - int err=0; - const EVP_MD *md; - - q=buf; - - if (s->s3->handshake_buffer) - if (!ssl3_digest_cached_records(s)) - return 0; EVP_MD_CTX_init(&ctx); - for (idx=0;ssl_get_handshake_digest(idx,&mask,&md);idx++) + for (i = 0; ssl_get_handshake_digest(i, &mask, &md); i++) { - if (mask & ssl_get_algorithm2(s)) - { - int hashsize = EVP_MD_size(md); - if (hashsize < 0 || hashsize > (int)(sizeof buf - (size_t)(q-buf))) + int hash_size; + unsigned int digest_len; + EVP_MD_CTX *hdgst = s->s3->handshake_dgst[i]; + + if ((mask & ssl_get_algorithm2(s)) == 0) + continue; + + hash_size = EVP_MD_size(md); + if (!hdgst || hash_size < 0 || (size_t)hash_size > out_len) { - /* internal error: 'buf' is too small for this cipersuite! */ err = 1; + break; } - else + + if (!EVP_MD_CTX_copy_ex(&ctx, hdgst) || + !EVP_DigestFinal_ex(&ctx, out, &digest_len) || + digest_len != (unsigned int)hash_size) /* internal error */ { - EVP_MD_CTX_copy_ex(&ctx,s->s3->handshake_dgst[idx]); - EVP_DigestFinal_ex(&ctx,q,&i); - if (i != (unsigned int)hashsize) /* can't really happen */ err = 1; - q+=i; + break; } + out += digest_len; + out_len -= digest_len; + len += digest_len; } + + EVP_MD_CTX_cleanup(&ctx); + + if (err != 0) + return -1; + return len; + } + +int tls1_final_finish_mac(SSL *s, + const char *str, int slen, unsigned char *out) + { + unsigned char buf[2*EVP_MAX_MD_SIZE]; + unsigned char buf2[12]; + int err=0; + int digests_len; + + if (s->s3->handshake_buffer) + if (!ssl3_digest_cached_records(s)) + return 0; + + digests_len = tls1_handshake_digest(s, buf, sizeof(buf)); + if (digests_len < 0) + { + err = 1; + digests_len = 0; } if (!tls1_PRF(ssl_get_algorithm2(s), - str,slen, buf,(int)(q-buf), NULL,0, NULL,0, NULL,0, + str,slen, buf, digests_len, NULL,0, NULL,0, NULL,0, s->session->master_key,s->session->master_key_length, out,buf2,sizeof buf2)) err = 1; - EVP_MD_CTX_cleanup(&ctx); if (err) return 0; diff -burN android-openssl.orig/ssl/t1_lib.c android-openssl/ssl/t1_lib.c --- android-openssl.orig/ssl/t1_lib.c 2014-05-05 16:45:02.789389340 +0200 +++ android-openssl/ssl/t1_lib.c 2014-05-05 16:46:32.549390565 +0200 @@ -2672,6 +2672,17 @@ EVP_DigestUpdate(md, kClientIDMagic, sizeof(kClientIDMagic)); + if (s->hit) + { + static const char kResumptionMagic[] = "Resumption"; + EVP_DigestUpdate(md, kResumptionMagic, + sizeof(kResumptionMagic)); + if (s->session->original_handshake_hash_len == 0) + return 0; + EVP_DigestUpdate(md, s->session->original_handshake_hash, + s->session->original_handshake_hash_len); + } + EVP_MD_CTX_init(&ctx); for (i = 0; i < SSL_MAX_DIGEST; i++) { @@ -2686,3 +2697,29 @@ return 1; } #endif + +/* tls1_record_handshake_hashes_for_channel_id records the current handshake + * hashes in |s->session| so that Channel ID resumptions can sign that data. */ +int tls1_record_handshake_hashes_for_channel_id(SSL *s) + { + int digest_len; + /* This function should never be called for a resumed session because + * the handshake hashes that we wish to record are for the original, + * full handshake. */ + if (s->hit) + return -1; + /* It only makes sense to call this function if Channel IDs have been + * negotiated. */ + if (!s->s3->tlsext_channel_id_valid) + return -1; + + digest_len = tls1_handshake_digest( + s, s->session->original_handshake_hash, + sizeof(s->session->original_handshake_hash)); + if (digest_len < 0) + return -1; + + s->session->original_handshake_hash_len = digest_len; + + return 1; + } diff -burN android-openssl.orig/ssl/tls1.h android-openssl/ssl/tls1.h --- android-openssl.orig/ssl/tls1.h 2014-05-05 16:45:02.697389339 +0200 +++ android-openssl/ssl/tls1.h 2014-05-05 16:46:32.553390566 +0200 @@ -249,7 +249,7 @@ #endif /* This is not an IANA defined extension number */ -#define TLSEXT_TYPE_channel_id 30031 +#define TLSEXT_TYPE_channel_id 30032 /* NameType value from RFC 3546 */ #define TLSEXT_NAMETYPE_host_name 0