#define NETSCAPE_HANG_BUG
+#include <assert.h>
#include <stdio.h>
#include <string.h>
}
s->init_num=0;
- s->s3->flags &= ~SSL3_FLAGS_SGC_RESTART_DONE;
- s->s3->flags &= ~TLS1_FLAGS_SKIP_CERT_VERIFY;
if (s->state != SSL_ST_RENEGOTIATE)
{
{
ret=ssl3_send_server_certificate(s);
if (ret <= 0) goto end;
- if (s->tlsext_status_expected)
+ if (s->s3->tmp.certificate_status_expected)
s->state=SSL3_ST_SW_CERT_STATUS_A;
else
s->state=SSL3_ST_SW_KEY_EXCH_A;
case SSL3_ST_SR_CERT_A:
case SSL3_ST_SR_CERT_B:
- /* Check for second client hello (MS SGC) */
- ret = ssl3_check_client_hello(s);
- if (ret <= 0)
- goto end;
- if (ret == 2)
- s->state = SSL3_ST_SR_CLNT_HELLO_C;
- else {
- if (s->s3->tmp.cert_request)
- {
- ret=ssl3_get_client_certificate(s);
- if (ret <= 0) goto end;
- }
- s->init_num=0;
- s->state=SSL3_ST_SR_KEY_EXCH_A;
- }
+ if (s->s3->tmp.cert_request)
+ {
+ ret=ssl3_get_client_certificate(s);
+ if (ret <= 0) goto end;
+ }
+ s->init_num=0;
+ s->state=SSL3_ST_SR_KEY_EXCH_A;
break;
case SSL3_ST_SR_KEY_EXCH_A:
ret=ssl3_get_client_key_exchange(s);
if (ret <= 0)
goto end;
- if (ret == 2)
- {
- /* For the ECDH ciphersuites when
- * the client sends its ECDH pub key in
- * a certificate, the CertificateVerify
- * message is not sent.
- */
- s->init_num = 0;
- s->state = SSL3_ST_SR_CHANGE;
- }
- else if (SSL_USE_SIGALGS(s))
- {
- s->state=SSL3_ST_SR_CERT_VRFY_A;
- s->init_num=0;
- if (!s->session->peer)
- break;
- /* For sigalgs freeze the handshake buffer
- * at this point and digest cached records.
- */
- if (!s->s3->handshake_buffer)
- {
- OPENSSL_PUT_ERROR(SSL, ssl3_accept, ERR_R_INTERNAL_ERROR);
- return -1;
- }
- s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE;
- if (!ssl3_digest_cached_records(s))
- return -1;
- }
- else
- {
- int offset=0;
- int dgst_num;
-
- s->state=SSL3_ST_SR_CERT_VRFY_A;
- s->init_num=0;
-
- /* We need to get hashes here so if there is
- * a client cert, it can be verified
- * FIXME - digest processing for CertificateVerify
- * should be generalized. But it is next step
- */
- if (s->s3->handshake_buffer)
- if (!ssl3_digest_cached_records(s))
- return -1;
- for (dgst_num=0; dgst_num<SSL_MAX_DIGEST;dgst_num++)
- if (s->s3->handshake_dgst[dgst_num])
- {
- int dgst_size;
-
- s->method->ssl3_enc->cert_verify_mac(s,EVP_MD_CTX_type(s->s3->handshake_dgst[dgst_num]),&(s->s3->tmp.cert_verify_md[offset]));
- dgst_size=EVP_MD_CTX_size(s->s3->handshake_dgst[dgst_num]);
- if (dgst_size < 0)
- {
- ret = -1;
- goto end;
- }
- offset+=dgst_size;
- }
- }
+ s->state=SSL3_ST_SR_CERT_VRFY_A;
+ s->init_num=0;
break;
case SSL3_ST_SR_CERT_VRFY_A:
case SSL3_ST_SR_CHANGE: {
char next_proto_neg = 0;
char channel_id = 0;
-# if !defined(OPENSSL_NO_NEXTPROTONEG)
next_proto_neg = s->s3->next_proto_neg_seen;
-# endif
channel_id = s->s3->tlsext_channel_id_valid;
/* At this point, the next message must be entirely
break;
}
-#if !defined(OPENSSL_NO_NEXTPROTONEG)
case SSL3_ST_SR_NEXT_PROTO_A:
case SSL3_ST_SR_NEXT_PROTO_B:
ret=ssl3_get_next_proto(s);
else
s->state=SSL3_ST_SR_FINISHED_A;
break;
-#endif
case SSL3_ST_SR_CHANNEL_ID_A:
case SSL3_ST_SR_CHANNEL_ID_B:
case SSL3_ST_SW_SESSION_TICKET_A:
case SSL3_ST_SW_SESSION_TICKET_B:
- ret=ssl3_send_newsession_ticket(s);
+ ret=ssl3_send_new_session_ticket(s);
if (ret <= 0) goto end;
s->state=SSL3_ST_SW_CHANGE_A;
s->init_num=0;
break;
+#if 0
+ // TODO(davidben): Implement OCSP stapling on the server.
case SSL3_ST_SW_CERT_STATUS_A:
case SSL3_ST_SW_CERT_STATUS_B:
ret=ssl3_send_cert_status(s);
s->state=SSL3_ST_SW_KEY_EXCH_A;
s->init_num=0;
break;
+#endif
case SSL3_ST_SW_CHANGE_A:
case SSL3_ST_SW_CHANGE_B:
return ssl_do_write(s);
}
-int ssl3_check_client_hello(SSL *s)
- {
- int ok;
- long n;
-
- /* this function is called when we really expect a Certificate message,
- * so permit appropriate message length */
- n=s->method->ssl_get_message(s,
- SSL3_ST_SR_CERT_A,
- SSL3_ST_SR_CERT_B,
- -1,
- s->max_cert_list,
- &ok);
- if (!ok) return((int)n);
- s->s3->tmp.reuse_message = 1;
- if (s->s3->tmp.message_type == SSL3_MT_CLIENT_HELLO)
- {
- /* We only allow the client to restart the handshake once per
- * negotiation. */
- if (s->s3->flags & SSL3_FLAGS_SGC_RESTART_DONE)
- {
- OPENSSL_PUT_ERROR(SSL, ssl3_check_client_hello, SSL_R_MULTIPLE_SGC_RESTARTS);
- return -1;
- }
- /* Throw away what we have done so far in the current handshake,
- * which will now be aborted. (A full SSL_clear would be too much.) */
-#ifndef OPENSSL_NO_DH
- if (s->s3->tmp.dh != NULL)
- {
- DH_free(s->s3->tmp.dh);
- s->s3->tmp.dh = NULL;
- }
-#endif
-#ifndef OPENSSL_NO_ECDH
- if (s->s3->tmp.ecdh != NULL)
- {
- EC_KEY_free(s->s3->tmp.ecdh);
- s->s3->tmp.ecdh = NULL;
- }
-#endif
- s->s3->flags |= SSL3_FLAGS_SGC_RESTART_DONE;
- return 2;
- }
- return 1;
-}
-
int ssl3_get_client_hello(SSL *s)
{
int i,ok,al=SSL_AD_INTERNAL_ERROR,ret= -1;
long n;
- SSL_CIPHER *c;
+ const SSL_CIPHER *c;
STACK_OF(SSL_CIPHER) *ciphers=NULL;
struct ssl_early_callback_ctx early_ctx;
CBS client_hello;
SSL3_ST_SR_CLNT_HELLO_B,
SSL3_MT_CLIENT_HELLO,
SSL3_RT_MAX_PLAIN_LENGTH,
+ SSL_GET_MESSAGE_HASH_MESSAGE,
&ok);
if (!ok) return((int)n);
if (s->ctx->app_verify_cookie_cb != NULL)
{
if (s->ctx->app_verify_cookie_cb(s,
- (unsigned char*)CBS_data(&cookie),
- CBS_len(&cookie)) == 0)
+ CBS_data(&cookie), CBS_len(&cookie)) == 0)
{
al=SSL_AD_HANDSHAKE_FAILURE;
OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_COOKIE_MISMATCH);
s->version = DTLS1_2_VERSION;
s->method = DTLSv1_2_server_method();
}
- else if (tls1_suiteb(s))
- {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
- s->version = s->client_version;
- al = SSL_AD_PROTOCOL_VERSION;
- goto f_err;
- }
else if (s->client_version <= DTLS1_VERSION &&
!(s->options & SSL_OP_NO_DTLSv1))
{
if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
{
- SSL_CIPHER *pref_cipher=NULL;
+ const SSL_CIPHER *pref_cipher=NULL;
s->session->master_key_length=sizeof(s->session->master_key);
if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
* s->tmp.new_cipher - the new cipher to use.
*/
- /* Handles TLS extensions that we couldn't check earlier */
- if (s->version >= SSL3_VERSION)
- {
- if (ssl_check_clienthello_tlsext_late(s) <= 0)
- {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_CLIENTHELLO_TLSEXT);
- goto err;
- }
- }
-
if (ret < 0) ret=-ret;
if (0)
{
int j,num;
unsigned char md_buf[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH];
unsigned int u;
-#ifndef OPENSSL_NO_DH
DH *dh=NULL,*dhp;
-#endif
-#ifndef OPENSSL_NO_ECDH
EC_KEY *ecdh=NULL, *ecdhp;
unsigned char *encodedPoint = NULL;
int encodedlen = 0;
int curve_id = 0;
BN_CTX *bn_ctx = NULL;
-#endif
const char* psk_identity_hint = NULL;
size_t psk_identity_hint_len = 0;
EVP_PKEY *pkey;
psk_identity_hint_len = 0;
n+=2+psk_identity_hint_len;
}
-#ifndef OPENSSL_NO_DH
if (alg_k & SSL_kEDH)
{
dhp=cert->dh_tmp;
r[2]=dh->pub_key;
}
else
-#endif
-#ifndef OPENSSL_NO_ECDH
if (alg_k & SSL_kEECDH)
{
const EC_GROUP *group;
r[3]=NULL;
}
else
-#endif /* !OPENSSL_NO_ECDH */
if (!(alg_k & SSL_kPSK))
{
al=SSL_AD_HANDSHAKE_FAILURE;
}
}
-#ifndef OPENSSL_NO_ECDH
if (alg_k & SSL_kEECDH)
{
/* XXX: For now, we only support named (not generic) curves.
encodedPoint = NULL;
p += encodedlen;
}
-#endif /* OPENSSL_NO_ECDH */
/* not anonymous */
if (pkey != NULL)
j=0;
for (num=2; num > 0; num--)
{
- EVP_DigestInit_ex(&md_ctx,(num == 2)
- ?s->ctx->md5:s->ctx->sha1, NULL);
+ EVP_DigestInit_ex(&md_ctx,
+ (num == 2) ? EVP_md5() : EVP_sha1(), NULL);
EVP_DigestUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
EVP_DigestUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
EVP_DigestUpdate(&md_ctx,d,n);
f_err:
ssl3_send_alert(s,SSL3_AL_FATAL,al);
err:
-#ifndef OPENSSL_NO_ECDH
if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
BN_CTX_free(bn_ctx);
-#endif
EVP_MD_CTX_cleanup(&md_ctx);
return(-1);
}
unsigned long alg_a;
uint8_t *premaster_secret = NULL;
size_t premaster_secret_len = 0;
- int skip_certificate_verify = 0;
RSA *rsa=NULL;
uint8_t *decrypt_buf = NULL;
EVP_PKEY *pkey=NULL;
-#ifndef OPENSSL_NO_DH
BIGNUM *pub=NULL;
- DH *dh_srvr, *dh_clnt = NULL;
-#endif
+ DH *dh_srvr;
-#ifndef OPENSSL_NO_ECDH
EC_KEY *srvr_ecdh = NULL;
EVP_PKEY *clnt_pub_pkey = NULL;
EC_POINT *clnt_ecpoint = NULL;
BN_CTX *bn_ctx = NULL;
unsigned int psk_len = 0;
unsigned char psk[PSK_MAX_PSK_LEN];
-#endif
n=s->method->ssl_get_message(s,
SSL3_ST_SR_KEY_EXCH_A,
SSL3_ST_SR_KEY_EXCH_B,
SSL3_MT_CLIENT_KEY_EXCHANGE,
2048, /* ??? */
+ SSL_GET_MESSAGE_HASH_MESSAGE,
&ok);
if (!ok) return((int)n);
}
/* Depending on the key exchange method, compute |premaster_secret| and
- * |premaster_secret_len|. Also, for DH and ECDH, set
- * |skip_certificate_verify| as appropriate. */
+ * |premaster_secret_len|. */
if (alg_k & SSL_kRSA)
{
CBS encrypted_premaster_secret;
}
rsa=pkey->pkey.rsa;
- /* TLS and [incidentally] DTLS{0xFEFF}
- *
- * TODO(davidben): Should this (and
- * ssl3_send_client_key_exchange) include DTLS1_BAD_VER?
- * Alternatively, get rid of DTLS1_BAD_VER?
- */
+ /* TLS and [incidentally] DTLS{0xFEFF} */
if (s->version > SSL3_VERSION)
{
CBS copy = client_key_exchange;
version_good = premaster_secret[0] ^ (s->client_version>>8);
version_good |= premaster_secret[1] ^ (s->client_version&0xff);
- /* The premaster secret must contain the same version number as
- * the ClientHello to detect version rollback attacks
- * (strangely, the protocol does not offer such protection for
- * DH ciphersuites). However, buggy clients exist that send the
- * negotiated protocol version instead if the server does not
- * support the requested protocol version. If
- * SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such clients. */
- if (s->options & SSL_OP_TLS_ROLLBACK_BUG)
- {
- unsigned char workaround_mask = version_good;
- unsigned char workaround;
-
- /* workaround_mask will be 0xff if version_good is
- * non-zero (i.e. the version match failed). Otherwise
- * it'll be 0x00. */
- workaround_mask |= workaround_mask >> 4;
- workaround_mask |= workaround_mask >> 2;
- workaround_mask |= workaround_mask >> 1;
- workaround_mask = ~((workaround_mask & 1) - 1);
-
- workaround = premaster_secret[0] ^ (s->version>>8);
- workaround |= premaster_secret[1] ^ (s->version&0xff);
-
- /* If workaround_mask is 0xff (i.e. there was a version
- * mismatch) then we copy the value of workaround over
- * version_good. */
- version_good = (workaround & workaround_mask) |
- (version_good & ~workaround_mask);
- }
-
/* If any bits in version_good are set then they'll poision
* decrypt_good_mask and cause rand_premaster_secret to be
* used. */
premaster_secret_len = sizeof(rand_premaster_secret);
}
-#ifndef OPENSSL_NO_DH
- else if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
+ else if (alg_k & SSL_kEDH)
{
CBS dh_Yc;
- int idx = -1;
int dh_len;
- EVP_PKEY *skey = NULL;
if (!CBS_get_u16_length_prefixed(&client_key_exchange, &dh_Yc) ||
+ CBS_len(&dh_Yc) == 0 ||
CBS_len(&client_key_exchange) != 0)
{
OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG);
goto f_err;
}
- if (alg_k & SSL_kDHr)
- idx = SSL_PKEY_DH_RSA;
- else if (alg_k & SSL_kDHd)
- idx = SSL_PKEY_DH_DSA;
- if (idx >= 0)
- {
- skey = s->cert->pkeys[idx].privatekey;
- if ((skey == NULL) ||
- (skey->type != EVP_PKEY_DH) ||
- (skey->pkey.dh == NULL))
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_MISSING_RSA_CERTIFICATE);
- goto f_err;
- }
- dh_srvr = skey->pkey.dh;
- }
- else if (s->s3->tmp.dh == NULL)
+ if (s->s3->tmp.dh == NULL)
{
al=SSL_AD_HANDSHAKE_FAILURE;
OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_MISSING_TMP_DH_KEY);
goto f_err;
}
- else
- dh_srvr=s->s3->tmp.dh;
+ dh_srvr=s->s3->tmp.dh;
- if (CBS_len(&dh_Yc) == 0)
- {
- /* Get pubkey from the client certificate. This is the
- * 'implicit' case of ClientDiffieHellman.
- *
- * TODO(davidben): Either lose this code or fix a bug
- * (or get the spec changed): if there is a fixed_dh
- * client certificate, per spec, the 'implicit' mode
- * MUST be used. This logic will still accept 'explicit'
- * mode. */
- EVP_PKEY *clkey=X509_get_pubkey(s->session->peer);
- if (clkey)
- {
- if (EVP_PKEY_cmp_parameters(clkey, skey) == 1)
- dh_clnt = EVP_PKEY_get1_DH(clkey);
- }
- if (dh_clnt == NULL)
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_MISSING_TMP_DH_KEY);
- goto f_err;
- }
- EVP_PKEY_free(clkey);
- pub = dh_clnt->pub_key;
- }
- else
- pub = BN_bin2bn(CBS_data(&dh_Yc), CBS_len(&dh_Yc), NULL);
+ pub = BN_bin2bn(CBS_data(&dh_Yc), CBS_len(&dh_Yc), NULL);
if (pub == NULL)
{
OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_BN_LIB);
DH_free(s->s3->tmp.dh);
s->s3->tmp.dh=NULL;
- if (dh_clnt)
- DH_free(dh_clnt);
- else
- BN_clear_free(pub);
+ BN_clear_free(pub);
pub=NULL;
premaster_secret_len = dh_len;
- if (dh_clnt)
- skip_certificate_verify = 1;
}
-#endif
-#ifndef OPENSSL_NO_ECDH
- else if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe))
+ else if (alg_k & SSL_kEECDH)
{
int field_size = 0, ecdh_len;
const EC_KEY *tkey;
const EC_GROUP *group;
const BIGNUM *priv_key;
+ CBS ecdh_Yc;
/* initialize structures for server's ECDH key pair */
if ((srvr_ecdh = EC_KEY_new()) == NULL)
goto err;
}
- /* Let's get server private key and group information */
- if (alg_k & (SSL_kECDHr|SSL_kECDHe))
- {
- /* use the certificate */
- tkey = s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec;
- }
- else
- {
- /* use the ephermeral values we saved when
- * generating the ServerKeyExchange msg.
- */
- tkey = s->s3->tmp.ecdh;
- }
+ /* Use the ephermeral values we saved when generating the
+ * ServerKeyExchange msg. */
+ tkey = s->s3->tmp.ecdh;
group = EC_KEY_get0_group(tkey);
priv_key = EC_KEY_get0_private_key(tkey);
goto err;
}
- if (CBS_len(&client_key_exchange) == 0)
+ /* Get client's public key from encoded point
+ * in the ClientKeyExchange message.
+ */
+ if (!CBS_get_u8_length_prefixed(&client_key_exchange, &ecdh_Yc) ||
+ CBS_len(&client_key_exchange) != 0)
{
- /* Client Publickey was in Client Certificate */
-
- if (alg_k & SSL_kEECDH)
- {
- al=SSL_AD_HANDSHAKE_FAILURE;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_MISSING_TMP_ECDH_KEY);
- goto f_err;
- }
- if (((clnt_pub_pkey=X509_get_pubkey(s->session->peer))
- == NULL) ||
- (clnt_pub_pkey->type != EVP_PKEY_EC))
- {
- /* XXX: For now, we do not support client
- * authentication using ECDH certificates
- * so this branch (n == 0L) of the code is
- * never executed. When that support is
- * added, we ought to ensure the key
- * received in the certificate is
- * authorized for key agreement.
- * ECDH_compute_key implicitly checks that
- * the two ECDH shares are for the same
- * group.
- */
- al=SSL_AD_HANDSHAKE_FAILURE;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_UNABLE_TO_DECODE_ECDH_CERTS);
- goto f_err;
- }
-
- if (EC_POINT_copy(clnt_ecpoint,
- EC_KEY_get0_public_key(clnt_pub_pkey->pkey.ec)) == 0)
- {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_EC_LIB);
- goto err;
- }
- /* Skip certificate verify processing */
- skip_certificate_verify = 1;
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_DECODE_ERROR);
+ goto f_err;
}
- else
- {
- CBS ecdh_Yc;
-
- /* Get client's public key from encoded point
- * in the ClientKeyExchange message.
- */
- if (!CBS_get_u8_length_prefixed(&client_key_exchange, &ecdh_Yc) ||
- CBS_len(&client_key_exchange) != 0)
- {
- al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_DECODE_ERROR);
- goto f_err;
- }
- if ((bn_ctx = BN_CTX_new()) == NULL)
- {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_MALLOC_FAILURE);
- goto err;
- }
+ if ((bn_ctx = BN_CTX_new()) == NULL)
+ {
+ OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
- if (!EC_POINT_oct2point(group, clnt_ecpoint,
- CBS_data(&ecdh_Yc), CBS_len(&ecdh_Yc), bn_ctx))
- {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_EC_LIB);
- goto err;
- }
+ if (!EC_POINT_oct2point(group, clnt_ecpoint,
+ CBS_data(&ecdh_Yc), CBS_len(&ecdh_Yc), bn_ctx))
+ {
+ OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_EC_LIB);
+ goto err;
}
/* Allocate a buffer for both the secret and the PSK. */
premaster_secret_len = ecdh_len;
}
-#endif
else if (alg_k & SSL_kPSK)
{
/* For plain PSK, other_secret is a block of 0s with the same
OPENSSL_cleanse(premaster_secret, premaster_secret_len);
OPENSSL_free(premaster_secret);
- return skip_certificate_verify ? 2 : 1;
+ return 1;
f_err:
ssl3_send_alert(s,SSL3_AL_FATAL,al);
err:
}
if (decrypt_buf)
OPENSSL_free(decrypt_buf);
-#ifndef OPENSSL_NO_ECDH
EVP_PKEY_free(clnt_pub_pkey);
EC_POINT_free(clnt_ecpoint);
if (srvr_ecdh != NULL)
EC_KEY_free(srvr_ecdh);
BN_CTX_free(bn_ctx);
-#endif
return(-1);
}
int ssl3_get_cert_verify(SSL *s)
{
- EVP_PKEY *pkey=NULL;
int al,ok,ret=0;
long n;
CBS certificate_verify, signature;
- int type = 0;
X509 *peer = s->session->peer;
+ EVP_PKEY *pkey = NULL;
const EVP_MD *md = NULL;
- EVP_MD_CTX mctx;
-
- EVP_MD_CTX_init(&mctx);
+ uint8_t digest[EVP_MAX_MD_SIZE];
+ size_t digest_length;
+ EVP_PKEY_CTX *pctx = NULL;
- /* Determine if a CertificateVerify message is expected at all. It is
- * important that this be determined before ssl_get_message is called,
- * so as not to process the ChangeCipherSpec message early. */
- if (peer != NULL)
- {
- pkey = X509_get_pubkey(peer);
- type = X509_certificate_type(peer,pkey);
- }
- if (!(type & EVP_PKT_SIGN))
+ /* Only RSA and ECDSA client certificates are supported, so a
+ * CertificateVerify is required if and only if there's a
+ * client certificate. */
+ if (peer == NULL)
{
- ret = 1;
- goto done_with_buffer;
+ if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
+ return -1;
+ return 1;
}
n=s->method->ssl_get_message(s,
SSL3_ST_SR_CERT_VRFY_B,
SSL3_MT_CERTIFICATE_VERIFY,
SSL3_RT_MAX_PLAIN_LENGTH,
+ SSL_GET_MESSAGE_DONT_HASH_MESSAGE,
&ok);
if (!ok)
+ return (int)n;
+
+ /* Filter out unsupported certificate types. */
+ pkey = X509_get_pubkey(peer);
+ if (!(X509_certificate_type(peer, pkey) & EVP_PKT_SIGN) ||
+ (pkey->type != EVP_PKEY_RSA && pkey->type != EVP_PKEY_EC))
{
- ret = (int)n;
- goto done;
+ al = SSL_AD_UNSUPPORTED_CERTIFICATE;
+ OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE);
+ goto f_err;
}
CBS_init(&certificate_verify, s->init_msg, n);
- /* We now have a signature that we need to verify. */
- /* TODO(davidben): This should share code with
- * ssl3_get_server_key_exchange. */
-
+ /* Determine the digest type if needbe. */
if (SSL_USE_SIGALGS(s))
{
if (!tls12_check_peer_sigalg(&md, &al, s, &certificate_verify, pkey))
goto f_err;
}
+ /* Compute the digest. */
+ if (!ssl3_cert_verify_hash(s, digest, &digest_length, &md, pkey))
+ goto err;
+
+ /* The handshake buffer is no longer necessary, and we may hash the
+ * current message.*/
+ if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
+ goto err;
+ ssl3_hash_current_message(s);
+
+ /* Parse and verify the signature. */
if (!CBS_get_u16_length_prefixed(&certificate_verify, &signature) ||
CBS_len(&certificate_verify) != 0)
{
goto f_err;
}
- if (SSL_USE_SIGALGS(s))
- {
- size_t hdatalen;
- const uint8_t *hdata;
- if (!BIO_mem_contents(s->s3->handshake_buffer, &hdata, &hdatalen))
- {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, ERR_R_INTERNAL_ERROR);
- al=SSL_AD_INTERNAL_ERROR;
- goto f_err;
- }
- if (!EVP_VerifyInit_ex(&mctx, md, NULL)
- || !EVP_VerifyUpdate(&mctx, hdata, hdatalen))
- {
- OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, ERR_R_EVP_LIB);
- al=SSL_AD_INTERNAL_ERROR;
- goto f_err;
- }
-
- if (EVP_VerifyFinal(&mctx,
- CBS_data(&signature), CBS_len(&signature),
- pkey) <= 0)
- {
- al=SSL_AD_DECRYPT_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_SIGNATURE);
- goto f_err;
- }
- }
- else
- if (pkey->type == EVP_PKEY_RSA)
- {
- if (!RSA_verify(NID_md5_sha1, s->s3->tmp.cert_verify_md,
- MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH,
- CBS_data(&signature), CBS_len(&signature),
- pkey->pkey.rsa))
- {
- al = SSL_AD_DECRYPT_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_RSA_SIGNATURE);
- goto f_err;
- }
- }
- else
-#ifndef OPENSSL_NO_DSA
- if (pkey->type == EVP_PKEY_DSA)
- {
- if (DSA_verify(pkey->save_type,
- &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
- SHA_DIGEST_LENGTH,
- CBS_data(&signature), CBS_len(&signature),
- pkey->pkey.dsa) <= 0)
- {
- /* bad signature */
- al = SSL_AD_DECRYPT_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_DSA_SIGNATURE);
- goto f_err;
- }
- }
- else
-#endif
-#ifndef OPENSSL_NO_ECDSA
- if (pkey->type == EVP_PKEY_EC)
- {
- if (!ECDSA_verify(pkey->save_type,
- &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
- SHA_DIGEST_LENGTH,
- CBS_data(&signature), CBS_len(&signature),
- pkey->pkey.ec))
- {
- /* bad signature */
- al = SSL_AD_DECRYPT_ERROR;
- OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_ECDSA_SIGNATURE);
- goto f_err;
- }
- }
- else
-#endif
+ pctx = EVP_PKEY_CTX_new(pkey, NULL);
+ if (pctx == NULL)
+ goto err;
+ if (!EVP_PKEY_verify_init(pctx) ||
+ !EVP_PKEY_CTX_set_signature_md(pctx, md) ||
+ !EVP_PKEY_verify(pctx, CBS_data(&signature), CBS_len(&signature),
+ digest, digest_length))
{
- OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, ERR_R_INTERNAL_ERROR);
- al=SSL_AD_UNSUPPORTED_CERTIFICATE;
+ al = SSL_AD_DECRYPT_ERROR;
+ OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_SIGNATURE);
goto f_err;
}
-
- ret=1;
+ ret = 1;
if (0)
{
f_err:
ssl3_send_alert(s,SSL3_AL_FATAL,al);
}
-done_with_buffer:
- /* There is no more need for the handshake buffer. */
- if (s->s3->handshake_buffer)
- {
- BIO_free(s->s3->handshake_buffer);
- s->s3->handshake_buffer = NULL;
- s->s3->flags &= ~TLS1_FLAGS_KEEP_HANDSHAKE;
- }
-done:
- EVP_MD_CTX_cleanup(&mctx);
+err:
+ EVP_PKEY_CTX_free(pctx);
EVP_PKEY_free(pkey);
return(ret);
}
SSL3_ST_SR_CERT_B,
-1,
s->max_cert_list,
+ SSL_GET_MESSAGE_HASH_MESSAGE,
&ok);
if (!ok) return((int)n);
}
/* send a new session ticket (not necessarily for a new session) */
-int ssl3_send_newsession_ticket(SSL *s)
+int ssl3_send_new_session_ticket(SSL *s)
{
if (s->state == SSL3_ST_SW_SESSION_TICKET_A)
{
return ssl_do_write(s);
}
+#if 0
int ssl3_send_cert_status(SSL *s)
{
if (s->state == SSL3_ST_SW_CERT_STATUS_A)
/* SSL3_ST_SW_CERT_STATUS_B */
return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
}
+#endif
-# ifndef OPENSSL_NO_NEXTPROTONEG
/* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It
* sets the next_proto member in s if found */
int ssl3_get_next_proto(SSL *s)
SSL3_ST_SR_NEXT_PROTO_B,
SSL3_MT_NEXT_PROTO,
514, /* See the payload format below */
+ SSL_GET_MESSAGE_HASH_MESSAGE,
&ok);
if (!ok)
return 1;
}
-# endif
/* ssl3_get_channel_id reads and verifies a ClientID handshake message. */
int ssl3_get_channel_id(SSL *s)
{
int ret = -1, ok;
long n;
+ EVP_MD_CTX md_ctx;
+ uint8_t channel_id_hash[SHA256_DIGEST_LENGTH];
+ unsigned int channel_id_hash_len;
const uint8_t *p;
uint16_t extension_type, expected_extension_type;
EC_GROUP* p256 = NULL;
BIGNUM x, y;
CBS encrypted_extensions, extension;
- if (s->state == SSL3_ST_SR_CHANNEL_ID_A && s->init_num == 0)
- {
- /* The first time that we're called we take the current
- * handshake hash and store it. */
- EVP_MD_CTX md_ctx;
- unsigned int len;
-
- EVP_MD_CTX_init(&md_ctx);
- EVP_DigestInit_ex(&md_ctx, EVP_sha256(), NULL);
- if (!tls1_channel_id_hash(&md_ctx, s))
- return -1;
- len = sizeof(s->s3->tlsext_channel_id);
- EVP_DigestFinal(&md_ctx, s->s3->tlsext_channel_id, &len);
- EVP_MD_CTX_cleanup(&md_ctx);
- }
-
n = s->method->ssl_get_message(s,
SSL3_ST_SR_CHANNEL_ID_A,
SSL3_ST_SR_CHANNEL_ID_B,
SSL3_MT_ENCRYPTED_EXTENSIONS,
2 + 2 + TLSEXT_CHANNEL_ID_SIZE,
+ SSL_GET_MESSAGE_DONT_HASH_MESSAGE,
&ok);
if (!ok)
return((int)n);
- ssl3_finish_mac(s, (unsigned char*)s->init_buf->data, s->init_num + 4);
+ /* Before incorporating the EncryptedExtensions message to the
+ * handshake hash, compute the hash that should have been signed. */
+ channel_id_hash_len = sizeof(channel_id_hash);
+ EVP_MD_CTX_init(&md_ctx);
+ if (!EVP_DigestInit_ex(&md_ctx, EVP_sha256(), NULL) ||
+ !tls1_channel_id_hash(&md_ctx, s) ||
+ !EVP_DigestFinal(&md_ctx, channel_id_hash, &channel_id_hash_len))
+ {
+ EVP_MD_CTX_cleanup(&md_ctx);
+ return -1;
+ }
+ EVP_MD_CTX_cleanup(&md_ctx);
+ assert(channel_id_hash_len == SHA256_DIGEST_LENGTH);
+
+ ssl3_hash_current_message(s);
/* s->state doesn't reflect whether ChangeCipherSpec has been received
* in this handshake, but s->s3->change_cipher_spec does (will be reset
/* We stored the handshake hash in |tlsext_channel_id| the first time
* that we were called. */
- switch (ECDSA_do_verify(s->s3->tlsext_channel_id, SHA256_DIGEST_LENGTH, &sig, key)) {
- case 1:
- break;
- case 0:
+ if (!ECDSA_do_verify(channel_id_hash, channel_id_hash_len, &sig, key))
+ {
OPENSSL_PUT_ERROR(SSL, ssl3_get_channel_id, SSL_R_CHANNEL_ID_SIGNATURE_INVALID);
s->s3->tlsext_channel_id_valid = 0;
goto err;
- default:
- s->s3->tlsext_channel_id_valid = 0;
- goto err;
- }
+ }
memcpy(s->s3->tlsext_channel_id, p, 64);
ret = 1;