summaryrefslogtreecommitdiffstats
path: root/ssl/s3_srvr.c
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2011-05-20 14:58:45 +0000
committerDr. Stephen Henson <steve@openssl.org>2011-05-20 14:58:45 +0000
commitb81fde02aa9c09b41ca83c59f885140d85cb9002 (patch)
treedc2855cc8fe1fb85ca20f65d4867109721033c0b /ssl/s3_srvr.c
parent57dd2ea808ea4564a5b1aa2dc4f7ce5b6811904b (diff)
Add server client certificate support for TLS v1.2 . This is more complex
than client side as we need to keep the handshake record cache frozen when it contains all the records need to process the certificate verify message. (backport from HEAD).
Diffstat (limited to 'ssl/s3_srvr.c')
-rw-r--r--ssl/s3_srvr.c113
1 files changed, 111 insertions, 2 deletions
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 9dc2a38750..861b0f3e3c 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -513,6 +513,9 @@ int ssl3_accept(SSL *s)
skip=1;
s->s3->tmp.cert_request=0;
s->state=SSL3_ST_SW_SRVR_DONE_A;
+ if (s->s3->handshake_buffer)
+ if (!ssl3_digest_cached_records(s))
+ return -1;
}
else
{
@@ -598,6 +601,24 @@ int ssl3_accept(SSL *s)
s->state=SSL3_ST_SR_FINISHED_A;
s->init_num = 0;
}
+ else if (s->version >= TLS1_2_VERSION)
+ {
+ s->state=SSL3_ST_SR_CERT_VRFY_A;
+ s->init_num=0;
+ if (!s->session->peer)
+ break;
+ /* For TLS v1.2 freeze the handshake buffer
+ * at this point and digest cached records.
+ */
+ if (!s->s3->handshake_buffer)
+ {
+ SSLerr(SSL_F_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;
@@ -1316,8 +1337,11 @@ int ssl3_get_client_hello(SSL *s)
s->s3->tmp.new_cipher=s->session->cipher;
}
- if (!ssl3_digest_cached_records(s))
- goto f_err;
+ if (s->version < TLS1_2_VERSION || !(s->verify_mode & SSL_VERIFY_PEER))
+ {
+ if (!ssl3_digest_cached_records(s))
+ goto f_err;
+ }
/* we now have the following setup.
* client_random
@@ -1963,6 +1987,14 @@ int ssl3_send_certificate_request(SSL *s)
p+=n;
n++;
+ if (s->version >= TLS1_2_VERSION)
+ {
+ nl = tls12_get_req_sig_algs(s, p + 2);
+ s2n(nl, p);
+ p += nl + 2;
+ n += nl + 2;
+ }
+
off=n;
p+=2;
n+=2;
@@ -2817,6 +2849,9 @@ int ssl3_get_cert_verify(SSL *s)
long n;
int type=0,i,j;
X509 *peer;
+ const EVP_MD *md = NULL;
+ EVP_MD_CTX mctx;
+ EVP_MD_CTX_init(&mctx);
n=s->method->ssl_get_message(s,
SSL3_ST_SR_CERT_VRFY_A,
@@ -2885,6 +2920,36 @@ int ssl3_get_cert_verify(SSL *s)
}
else
{
+ if (s->version >= TLS1_2_VERSION)
+ {
+ int sigalg = tls12_get_sigid(pkey);
+ /* Should never happen */
+ if (sigalg == -1)
+ {
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,ERR_R_INTERNAL_ERROR);
+ al=SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+ /* Check key type is consistent with signature */
+ if (sigalg != (int)p[1])
+ {
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_WRONG_SIGNATURE_TYPE);
+ al=SSL_AD_DECODE_ERROR;
+ goto f_err;
+ }
+ md = tls12_get_hash(p[0]);
+ if (md == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNKNOWN_DIGEST);
+ al=SSL_AD_DECODE_ERROR;
+ goto f_err;
+ }
+#ifdef SSL_DEBUG
+fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
+#endif
+ p += 2;
+ n -= 2;
+ }
n2s(p,i);
n-=2;
if (i > n)
@@ -2902,6 +2967,37 @@ int ssl3_get_cert_verify(SSL *s)
goto f_err;
}
+ if (s->version >= TLS1_2_VERSION)
+ {
+ long hdatalen = 0;
+ void *hdata;
+ hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
+ if (hdatalen <= 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
+ al=SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+#ifdef SSL_DEBUG
+ fprintf(stderr, "Using TLS 1.2 with client verify alg %s\n",
+ EVP_MD_name(md));
+#endif
+ if (!EVP_VerifyInit_ex(&mctx, md, NULL)
+ || !EVP_VerifyUpdate(&mctx, hdata, hdatalen))
+ {
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, ERR_R_EVP_LIB);
+ al=SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+
+ if (EVP_VerifyFinal(&mctx, p , i, pkey) <= 0)
+ {
+ al=SSL_AD_DECRYPT_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_BAD_SIGNATURE);
+ goto f_err;
+ }
+ }
+ else
#ifndef OPENSSL_NO_RSA
if (pkey->type == EVP_PKEY_RSA)
{
@@ -2992,6 +3088,13 @@ f_err:
ssl3_send_alert(s,SSL3_AL_FATAL,al);
}
end:
+ if (s->s3->handshake_buffer)
+ {
+ BIO_free(s->s3->handshake_buffer);
+ s->s3->handshake_buffer = NULL;
+ s->s3->flags &= ~TLS1_FLAGS_KEEP_HANDSHAKE;
+ }
+ EVP_MD_CTX_cleanup(&mctx);
EVP_PKEY_free(pkey);
return(ret);
}
@@ -3104,6 +3207,12 @@ int ssl3_get_client_certificate(SSL *s)
al=SSL_AD_HANDSHAKE_FAILURE;
goto f_err;
}
+ /* No client certificate so digest cached records */
+ if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
+ {
+ al=SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
}
else
{