ChannelID support. Implement ChannelID as both a client and server.
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index ba0410a..af664de 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c
@@ -465,13 +465,14 @@ SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B); if (ret <= 0) goto end; -#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG) - s->state=SSL3_ST_CW_FINISHED_A; -#else + s->state=SSL3_ST_CW_FINISHED_A; +#if !defined(OPENSSL_NO_TLSEXT) + if (s->s3->tlsext_channel_id_valid) + s->state=SSL3_ST_CW_CHANNEL_ID_A; +# if !defined(OPENSSL_NO_NEXTPROTONEG) if (s->s3->next_proto_neg_seen) s->state=SSL3_ST_CW_NEXT_PROTO_A; - else - s->state=SSL3_ST_CW_FINISHED_A; +# endif #endif s->init_num=0; @@ -497,6 +498,18 @@ case SSL3_ST_CW_NEXT_PROTO_B: ret=ssl3_send_next_proto(s); if (ret <= 0) goto end; + if (s->s3->tlsext_channel_id_valid) + s->state=SSL3_ST_CW_CHANNEL_ID_A; + else + s->state=SSL3_ST_CW_FINISHED_A; + break; +#endif + +#if !defined(OPENSSL_NO_TLSEXT) + case SSL3_ST_CW_CHANNEL_ID_A: + case SSL3_ST_CW_CHANNEL_ID_B: + ret=ssl3_send_channel_id(s); + if (ret <= 0) goto end; s->state=SSL3_ST_CW_FINISHED_A; break; #endif @@ -524,6 +537,18 @@ } else { + /* 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. */ + if (s->s3->tlsext_channel_id_new) + { + ret = tls1_record_handshake_hashes_for_channel_id(s); + if (ret <= 0) + goto end; + } if ((SSL_get_mode(s) & SSL_MODE_HANDSHAKE_CUTTHROUGH) && ssl3_can_cutthrough(s) && s->s3->previous_server_finished_len == 0 /* no cutthrough on renegotiation (would complicate the state machine) */ @@ -3135,7 +3160,8 @@ return(0); } -#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) +#if !defined(OPENSSL_NO_TLSEXT) +# if !defined(OPENSSL_NO_NEXTPROTONEG) int ssl3_send_next_proto(SSL *s) { unsigned int len, padding_len; @@ -3159,7 +3185,136 @@ return ssl3_do_write(s, SSL3_RT_HANDSHAKE); } -#endif /* !OPENSSL_NO_TLSEXT && !OPENSSL_NO_NEXTPROTONEG */ + +# endif /* !OPENSSL_NO_NEXTPROTONEG */ + +int ssl3_send_channel_id(SSL *s) + { + unsigned char *d; + int ret = -1, public_key_len; + EVP_MD_CTX md_ctx; + size_t sig_len; + ECDSA_SIG *sig = NULL; + unsigned char *public_key = NULL, *derp, *der_sig = NULL; + + if (s->state != SSL3_ST_CW_CHANNEL_ID_A) + return ssl3_do_write(s, SSL3_RT_HANDSHAKE); + + if (!s->tlsext_channel_id_private && s->ctx->channel_id_cb) + { + EVP_PKEY *key = NULL; + s->ctx->channel_id_cb(s, &key); + if (key != NULL) + { + s->tlsext_channel_id_private = key; + } + } + if (!s->tlsext_channel_id_private) + { + s->rwstate=SSL_CHANNEL_ID_LOOKUP; + return (-1); + } + s->rwstate=SSL_NOTHING; + + d = (unsigned char *)s->init_buf->data; + *(d++)=SSL3_MT_ENCRYPTED_EXTENSIONS; + l2n3(2 + 2 + TLSEXT_CHANNEL_ID_SIZE, d); + if (s->s3->tlsext_channel_id_new) + s2n(TLSEXT_TYPE_channel_id_new, d); + else + s2n(TLSEXT_TYPE_channel_id, d); + s2n(TLSEXT_CHANNEL_ID_SIZE, d); + + EVP_MD_CTX_init(&md_ctx); + + public_key_len = i2d_PublicKey(s->tlsext_channel_id_private, NULL); + if (public_key_len <= 0) + { + OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id, SSL_R_CANNOT_SERIALIZE_PUBLIC_KEY); + goto err; + } + /* i2d_PublicKey will produce an ANSI X9.62 public key which, for a + * P-256 key, is 0x04 (meaning uncompressed) followed by the x and y + * field elements as 32-byte, big-endian numbers. */ + if (public_key_len != 65) + { + OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id, SSL_R_CHANNEL_ID_NOT_P256); + goto err; + } + public_key = OPENSSL_malloc(public_key_len); + if (!public_key) + { + OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id, ERR_R_MALLOC_FAILURE); + goto err; + } + + derp = public_key; + i2d_PublicKey(s->tlsext_channel_id_private, &derp); + + if (EVP_DigestSignInit(&md_ctx, NULL, EVP_sha256(), NULL, + s->tlsext_channel_id_private) != 1) + { + OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id, SSL_R_EVP_DIGESTSIGNINIT_FAILED); + goto err; + } + + if (!tls1_channel_id_hash(&md_ctx, s)) + goto err; + + if (!EVP_DigestSignFinal(&md_ctx, NULL, &sig_len)) + { + OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id, SSL_R_EVP_DIGESTSIGNFINAL_FAILED); + goto err; + } + + der_sig = OPENSSL_malloc(sig_len); + if (!der_sig) + { + OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EVP_DigestSignFinal(&md_ctx, der_sig, &sig_len)) + { + OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id, SSL_R_EVP_DIGESTSIGNFINAL_FAILED); + goto err; + } + + derp = der_sig; + sig = d2i_ECDSA_SIG(NULL, (const unsigned char**) &derp, sig_len); + if (sig == NULL) + { + OPENSSL_PUT_ERROR(SSL, ssl3_send_channel_id, SSL_R_D2I_ECDSA_SIG); + goto err; + } + + /* The first byte of public_key will be 0x4, denoting an uncompressed key. */ + memcpy(d, public_key + 1, 64); + d += 64; + memset(d, 0, 2 * 32); + BN_bn2bin(sig->r, d + 32 - BN_num_bytes(sig->r)); + d += 32; + BN_bn2bin(sig->s, d + 32 - BN_num_bytes(sig->s)); + d += 32; + + s->state = SSL3_ST_CW_CHANNEL_ID_B; + s->init_num = 4 + 2 + 2 + TLSEXT_CHANNEL_ID_SIZE; + s->init_off = 0; + + ret = ssl3_do_write(s, SSL3_RT_HANDSHAKE); + +err: + EVP_MD_CTX_cleanup(&md_ctx); + if (public_key) + OPENSSL_free(public_key); + if (der_sig) + OPENSSL_free(der_sig); + if (sig) + ECDSA_SIG_free(sig); + + return ret; + } +#endif /* !OPENSSL_NO_TLSEXT */ /* Check to see if handshake is full or resumed. Usually this is just a * case of checking to see if a cache hit has occurred. In the case of