summaryrefslogtreecommitdiff
path: root/ssl/s3_srvr.c
diff options
context:
space:
mode:
Diffstat (limited to 'ssl/s3_srvr.c')
-rw-r--r--ssl/s3_srvr.c290
1 files changed, 81 insertions, 209 deletions
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 9ec6885..0e9c7d5 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -148,6 +148,7 @@
#define NETSCAPE_HANG_BUG
+#include <assert.h>
#include <stdio.h>
#include <string.h>
@@ -351,7 +352,7 @@ int ssl3_accept(SSL *s)
{
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;
@@ -485,54 +486,6 @@ int ssl3_accept(SSL *s)
goto end;
s->state=SSL3_ST_SR_CERT_VRFY_A;
s->init_num=0;
-
- /* TODO(davidben): These two blocks are different
- * between SSL and DTLS. Resolve the difference and code
- * duplication. */
- if (SSL_USE_SIGALGS(s))
- {
- 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;
-
- /* 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;
- }
- }
break;
case SSL3_ST_SR_CERT_VRFY_A:
@@ -547,9 +500,7 @@ int ssl3_accept(SSL *s)
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
@@ -568,7 +519,6 @@ int ssl3_accept(SSL *s)
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);
@@ -579,7 +529,6 @@ int ssl3_accept(SSL *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:
@@ -614,12 +563,14 @@ int ssl3_accept(SSL *s)
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);
@@ -627,6 +578,7 @@ int ssl3_accept(SSL *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:
@@ -778,6 +730,7 @@ int ssl3_get_client_hello(SSL *s)
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);
@@ -1187,16 +1140,6 @@ int ssl3_get_client_hello(SSL *s)
* 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)
{
@@ -1326,16 +1269,12 @@ int ssl3_send_server_key_exchange(SSL *s)
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;
@@ -1372,7 +1311,6 @@ int ssl3_send_server_key_exchange(SSL *s)
psk_identity_hint_len = 0;
n+=2+psk_identity_hint_len;
}
-#ifndef OPENSSL_NO_DH
if (alg_k & SSL_kEDH)
{
dhp=cert->dh_tmp;
@@ -1424,8 +1362,6 @@ int ssl3_send_server_key_exchange(SSL *s)
r[2]=dh->pub_key;
}
else
-#endif
-#ifndef OPENSSL_NO_ECDH
if (alg_k & SSL_kEECDH)
{
const EC_GROUP *group;
@@ -1550,7 +1486,6 @@ int ssl3_send_server_key_exchange(SSL *s)
r[3]=NULL;
}
else
-#endif /* !OPENSSL_NO_ECDH */
if (!(alg_k & SSL_kPSK))
{
al=SSL_AD_HANDSHAKE_FAILURE;
@@ -1607,7 +1542,6 @@ int ssl3_send_server_key_exchange(SSL *s)
}
}
-#ifndef OPENSSL_NO_ECDH
if (alg_k & SSL_kEECDH)
{
/* XXX: For now, we only support named (not generic) curves.
@@ -1631,7 +1565,6 @@ int ssl3_send_server_key_exchange(SSL *s)
encodedPoint = NULL;
p += encodedlen;
}
-#endif /* OPENSSL_NO_ECDH */
/* not anonymous */
if (pkey != NULL)
@@ -1715,10 +1648,8 @@ int ssl3_send_server_key_exchange(SSL *s)
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);
}
@@ -1823,25 +1754,22 @@ int ssl3_get_client_key_exchange(SSL *s)
RSA *rsa=NULL;
uint8_t *decrypt_buf = NULL;
EVP_PKEY *pkey=NULL;
-#ifndef OPENSSL_NO_DH
BIGNUM *pub=NULL;
DH *dh_srvr;
-#endif
-#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);
@@ -2063,7 +1991,6 @@ int ssl3_get_client_key_exchange(SSL *s)
premaster_secret_len = sizeof(rand_premaster_secret);
}
-#ifndef OPENSSL_NO_DH
else if (alg_k & SSL_kEDH)
{
CBS dh_Yc;
@@ -2116,9 +2043,7 @@ int ssl3_get_client_key_exchange(SSL *s)
premaster_secret_len = dh_len;
}
-#endif
-#ifndef OPENSSL_NO_ECDH
else if (alg_k & SSL_kEECDH)
{
int field_size = 0, ecdh_len;
@@ -2213,7 +2138,6 @@ int ssl3_get_client_key_exchange(SSL *s)
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
@@ -2283,41 +2207,34 @@ 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);
-
- /* 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))
+ uint8_t digest[EVP_MAX_MD_SIZE];
+ size_t digest_length;
+ EVP_PKEY_CTX *pctx = NULL;
+
+ /* 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,
@@ -2325,26 +2242,42 @@ int ssl3_get_cert_verify(SSL *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)
{
@@ -2353,87 +2286,27 @@ int ssl3_get_cert_verify(SSL *s)
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_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);
}
@@ -2453,6 +2326,7 @@ int ssl3_get_client_certificate(SSL *s)
SSL3_ST_SR_CERT_B,
-1,
s->max_cert_list,
+ SSL_GET_MESSAGE_HASH_MESSAGE,
&ok);
if (!ok) return((int)n);
@@ -2643,7 +2517,7 @@ int ssl3_send_server_certificate(SSL *s)
}
/* 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)
{
@@ -2770,6 +2644,7 @@ int ssl3_send_newsession_ticket(SSL *s)
return ssl_do_write(s);
}
+#if 0
int ssl3_send_cert_status(SSL *s)
{
if (s->state == SSL3_ST_SW_CERT_STATUS_A)
@@ -2804,8 +2679,8 @@ int ssl3_send_cert_status(SSL *s)
/* 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)
@@ -2827,6 +2702,7 @@ 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)
@@ -2863,13 +2739,15 @@ int ssl3_get_next_proto(SSL *s)
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;
@@ -2879,33 +2757,32 @@ int ssl3_get_channel_id(SSL *s)
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
@@ -2978,17 +2855,12 @@ int ssl3_get_channel_id(SSL *s)
/* 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;