summaryrefslogtreecommitdiffstats
path: root/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'ssl')
-rw-r--r--ssl/ssl_conf.c7
-rw-r--r--ssl/ssl_err.c19
-rw-r--r--ssl/ssl_lib.c54
-rw-r--r--ssl/ssl_locl.h22
-rw-r--r--ssl/statem/extensions.c17
-rw-r--r--ssl/statem/extensions_clnt.c42
-rw-r--r--ssl/statem/extensions_cust.c1
-rw-r--r--ssl/statem/extensions_srvr.c14
-rw-r--r--ssl/statem/statem_clnt.c75
-rw-r--r--ssl/statem/statem_lib.c111
-rw-r--r--ssl/statem/statem_locl.h10
-rw-r--r--ssl/statem/statem_srvr.c121
-rw-r--r--ssl/t1_trce.c3
13 files changed, 443 insertions, 53 deletions
diff --git a/ssl/ssl_conf.c b/ssl/ssl_conf.c
index 0cd8ace437..cb4ff8daad 100644
--- a/ssl/ssl_conf.c
+++ b/ssl/ssl_conf.c
@@ -386,7 +386,12 @@ static int cmd_VerifyMode(SSL_CONF_CTX *cctx, const char *value)
SSL_FLAG_VFY_SRV("Request", SSL_VERIFY_PEER),
SSL_FLAG_VFY_SRV("Require",
SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT),
- SSL_FLAG_VFY_SRV("Once", SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE)
+ SSL_FLAG_VFY_SRV("Once", SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE),
+ SSL_FLAG_VFY_SRV("RequestPostHandshake",
+ SSL_VERIFY_PEER | SSL_VERIFY_POST_HANDSHAKE),
+ SSL_FLAG_VFY_SRV("RequirePostHandshake",
+ SSL_VERIFY_PEER | SSL_VERIFY_POST_HANDSHAKE |
+ SSL_VERIFY_FAIL_IF_NO_PEER_CERT),
};
if (value == NULL)
return -3;
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 746678cb39..f0bde60994 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -351,6 +351,8 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_VALIDATE_CT, 0), "ssl_validate_ct"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_VERIFY_CERT_CHAIN, 0),
"ssl_verify_cert_chain"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_VERIFY_CLIENT_POST_HANDSHAKE, 0),
+ "SSL_verify_client_post_handshake"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_WRITE, 0), "SSL_write"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_WRITE_EARLY_DATA, 0),
"SSL_write_early_data"},
@@ -369,6 +371,10 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS13_GENERATE_SECRET, 0),
"tls13_generate_secret"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS13_HKDF_EXPAND, 0), "tls13_hkdf_expand"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS13_RESTORE_HANDSHAKE_DIGEST_FOR_PHA, 0),
+ "tls13_restore_handshake_digest_for_pha"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS13_SAVE_HANDSHAKE_DIGEST_FOR_PHA, 0),
+ "tls13_save_handshake_digest_for_pha"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS13_SETUP_KEY_BLOCK, 0),
"tls13_setup_key_block"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS1_CHANGE_CIPHER_STATE, 0),
@@ -441,6 +447,8 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
"tls_construct_ctos_npn"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_PADDING, 0),
"tls_construct_ctos_padding"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_POST_HANDSHAKE_AUTH, 0),
+ "tls_construct_ctos_post_handshake_auth"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_PSK, 0),
"tls_construct_ctos_psk"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_PSK_KEX_MODES, 0),
@@ -557,6 +565,8 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
"tls_parse_ctos_key_share"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_MAXFRAGMENTLEN, 0),
"tls_parse_ctos_maxfragmentlen"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_POST_HANDSHAKE_AUTH, 0),
+ "tls_parse_ctos_post_handshake_auth"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_PSK, 0), "tls_parse_ctos_psk"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_PSK_KEX_MODES, 0),
"tls_parse_ctos_psk_kex_modes"},
@@ -832,6 +842,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
"exceeds max fragment size"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EXCESSIVE_MESSAGE_SIZE),
"excessive message size"},
+ {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EXTENSION_NOT_RECEIVED),
+ "extension not received"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EXTRA_DATA_IN_MESSAGE),
"extra data in message"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EXT_LENGTH_MISMATCH),
@@ -868,8 +880,10 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_COMMAND), "invalid command"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_COMPRESSION_ALGORITHM),
"invalid compression algorithm"},
+ {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_CONFIG), "invalid config"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_CONFIGURATION_NAME),
"invalid configuration name"},
+ {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_CONTEXT), "invalid context"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_CT_VALIDATION_TYPE),
"invalid ct validation type"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_KEY_UPDATE_TYPE),
@@ -919,6 +933,7 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
"missing tmp ecdh key"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NOT_ON_RECORD_BOUNDARY),
"not on record boundary"},
+ {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NOT_SERVER), "not server"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_APPLICATION_PROTOCOL),
"no application protocol"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CERTIFICATES_RETURNED),
@@ -978,6 +993,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
"pem name bad prefix"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEM_NAME_TOO_SHORT), "pem name too short"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PIPELINE_FAILURE), "pipeline failure"},
+ {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_POST_HANDSHAKE_AUTH_ENCODING_ERR),
+ "post handshake auth encoding err"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PROTOCOL_IS_SHUTDOWN),
"protocol is shutdown"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PSK_IDENTITY_NOT_FOUND),
@@ -996,6 +1013,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
"renegotiation encoding err"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RENEGOTIATION_MISMATCH),
"renegotiation mismatch"},
+ {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REQUEST_PENDING), "request pending"},
+ {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REQUEST_SENT), "request sent"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REQUIRED_CIPHER_MISSING),
"required cipher missing"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REQUIRED_COMPRESSION_ALGORITHM_MISSING),
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 270d4de593..5a5fbad1f6 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1186,6 +1186,8 @@ void SSL_free(SSL *s)
OPENSSL_free(s->ext.alpn);
OPENSSL_free(s->ext.tls13_cookie);
OPENSSL_free(s->clienthello);
+ OPENSSL_free(s->pha_context);
+ EVP_MD_CTX_free(s->pha_dgst);
sk_X509_NAME_pop_free(s->ca_names, X509_NAME_free);
@@ -5318,3 +5320,55 @@ int SSL_stateless(SSL *s)
return 0;
}
+
+void SSL_force_post_handshake_auth(SSL *ssl)
+{
+ ssl->pha_forced = 1;
+}
+
+int SSL_verify_client_post_handshake(SSL *ssl)
+{
+ if (!SSL_IS_TLS13(ssl)) {
+ SSLerr(SSL_F_SSL_VERIFY_CLIENT_POST_HANDSHAKE, SSL_R_WRONG_SSL_VERSION);
+ return 0;
+ }
+ if (!ssl->server) {
+ SSLerr(SSL_F_SSL_VERIFY_CLIENT_POST_HANDSHAKE, SSL_R_NOT_SERVER);
+ return 0;
+ }
+
+ if (!SSL_is_init_finished(ssl)) {
+ SSLerr(SSL_F_SSL_VERIFY_CLIENT_POST_HANDSHAKE, SSL_R_STILL_IN_INIT);
+ return 0;
+ }
+
+ switch (ssl->post_handshake_auth) {
+ case SSL_PHA_NONE:
+ SSLerr(SSL_F_SSL_VERIFY_CLIENT_POST_HANDSHAKE, SSL_R_EXTENSION_NOT_RECEIVED);
+ return 0;
+ default:
+ case SSL_PHA_EXT_SENT:
+ SSLerr(SSL_F_SSL_VERIFY_CLIENT_POST_HANDSHAKE, ERR_R_INTERNAL_ERROR);
+ return 0;
+ case SSL_PHA_EXT_RECEIVED:
+ break;
+ case SSL_PHA_REQUEST_PENDING:
+ SSLerr(SSL_F_SSL_VERIFY_CLIENT_POST_HANDSHAKE, SSL_R_REQUEST_PENDING);
+ return 0;
+ case SSL_PHA_REQUESTED:
+ SSLerr(SSL_F_SSL_VERIFY_CLIENT_POST_HANDSHAKE, SSL_R_REQUEST_SENT);
+ return 0;
+ }
+
+ ssl->post_handshake_auth = SSL_PHA_REQUEST_PENDING;
+
+ /* checks verify_mode and algorithm_auth */
+ if (!send_certificate_request(ssl)) {
+ ssl->post_handshake_auth = SSL_PHA_EXT_RECEIVED; /* restore on error */
+ SSLerr(SSL_F_SSL_VERIFY_CLIENT_POST_HANDSHAKE, SSL_R_INVALID_CONFIG);
+ return 0;
+ }
+
+ ossl_statem_set_in_init(ssl, 1);
+ return 1;
+}
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 6afd0091cf..221d5b903a 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -402,6 +402,15 @@
#define CERT_PRIVATE_KEY 2
*/
+/* Post-Handshake Authentication state */
+typedef enum {
+ SSL_PHA_NONE = 0,
+ SSL_PHA_EXT_SENT, /* client-side only: extension sent */
+ SSL_PHA_EXT_RECEIVED, /* server-side only: extension received */
+ SSL_PHA_REQUEST_PENDING, /* server-side only: request pending */
+ SSL_PHA_REQUESTED /* request received by client, or sent by server */
+} SSL_PHA_STATE;
+
/* CipherSuite length. SSLv3 and all TLS versions. */
# define TLS_CIPHER_LEN 2
/* used to hold info on the particular ciphers used */
@@ -702,6 +711,7 @@ typedef enum tlsext_index_en {
TLSEXT_IDX_signed_certificate_timestamp,
TLSEXT_IDX_extended_master_secret,
TLSEXT_IDX_signature_algorithms_cert,
+ TLSEXT_IDX_post_handshake_auth,
TLSEXT_IDX_signature_algorithms,
TLSEXT_IDX_supported_versions,
TLSEXT_IDX_psk_kex_modes,
@@ -1334,6 +1344,14 @@ struct ssl_st {
int renegotiate;
/* If sending a KeyUpdate is pending */
int key_update;
+ /* Post-handshake authentication state */
+ SSL_PHA_STATE post_handshake_auth;
+ int pha_forced;
+ uint8_t* pha_context;
+ size_t pha_context_len;
+ int certreqs_sent;
+ EVP_MD_CTX *pha_dgst; /* this is just the digest through ClientFinished */
+
# ifndef OPENSSL_NO_SRP
/* ctx for SRP authentication */
SRP_CTX srp_ctx;
@@ -2535,6 +2553,10 @@ __owur int srp_generate_server_master_secret(SSL *s);
__owur int srp_generate_client_master_secret(SSL *s);
__owur int srp_verify_server_param(SSL *s);
+/* statem/statem_srvr.c */
+
+__owur int send_certificate_request(SSL *s);
+
/* statem/extensions_cust.c */
custom_ext_method *custom_ext_find(const custom_ext_methods *exts,
diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c
index 5ad86f20af..2faba13fd0 100644
--- a/ssl/statem/extensions.c
+++ b/ssl/statem/extensions.c
@@ -56,6 +56,8 @@ static int final_sig_algs(SSL *s, unsigned int context, int sent);
static int final_early_data(SSL *s, unsigned int context, int sent);
static int final_maxfragmentlen(SSL *s, unsigned int context, int sent);
+static int init_post_handshake_auth(SSL *s, unsigned int context);
+
/* Structure to define a built-in extension */
typedef struct extensions_definition_st {
/* The defined type for the extension */
@@ -290,6 +292,14 @@ static const EXTENSION_DEFINITION ext_defs[] = {
NULL, NULL, NULL
},
{
+ TLSEXT_TYPE_post_handshake_auth,
+ SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ONLY,
+ init_post_handshake_auth,
+ tls_parse_ctos_post_handshake_auth, NULL,
+ NULL, tls_construct_ctos_post_handshake_auth,
+ NULL,
+ },
+ {
TLSEXT_TYPE_signature_algorithms,
SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST,
init_sig_algs, tls_parse_ctos_sig_algs,
@@ -1653,3 +1663,10 @@ static int final_maxfragmentlen(SSL *s, unsigned int context, int sent)
return 1;
}
+
+static int init_post_handshake_auth(SSL *s, unsigned int context)
+{
+ s->post_handshake_auth = SSL_PHA_NONE;
+
+ return 1;
+}
diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
index 5441e98267..6286242ad5 100644
--- a/ssl/statem/extensions_clnt.c
+++ b/ssl/statem/extensions_clnt.c
@@ -1133,6 +1133,48 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context,
#endif
}
+EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL *s, WPACKET *pkt,
+ unsigned int context,
+ X509 *x, size_t chainidx)
+{
+#ifndef OPENSSL_NO_TLS1_3
+ if (!s->pha_forced) {
+ int i, n = 0;
+
+ /* check for cert, if present, we can do post-handshake auth */
+ if (s->cert == NULL)
+ return EXT_RETURN_NOT_SENT;
+
+ for (i = 0; i < SSL_PKEY_NUM; i++) {
+ if (s->cert->pkeys[i].x509 != NULL
+ && s->cert->pkeys[i].privatekey != NULL)
+ n++;
+ }
+
+ /* no identity certificates, so no extension */
+ if (n == 0)
+ return EXT_RETURN_NOT_SENT;
+ }
+
+ /* construct extension - 0 length, no contents */
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_post_handshake_auth)
+ || !WPACKET_start_sub_packet_u16(pkt)
+ || !WPACKET_close(pkt)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_CONSTRUCT_CTOS_POST_HANDSHAKE_AUTH,
+ ERR_R_INTERNAL_ERROR);
+ return EXT_RETURN_FAIL;
+ }
+
+ s->post_handshake_auth = SSL_PHA_EXT_SENT;
+
+ return EXT_RETURN_SENT;
+#else
+ return EXT_RETURN_NOT_SENT;
+#endif
+}
+
+
/*
* Parse the server's renegotiation binding and abort if it's not right
*/
diff --git a/ssl/statem/extensions_cust.c b/ssl/statem/extensions_cust.c
index 0a23630cf2..60a7c37bb1 100644
--- a/ssl/statem/extensions_cust.c
+++ b/ssl/statem/extensions_cust.c
@@ -525,6 +525,7 @@ int SSL_extension_supported(unsigned int ext_type)
case TLSEXT_TYPE_early_data:
case TLSEXT_TYPE_certificate_authorities:
case TLSEXT_TYPE_psk:
+ case TLSEXT_TYPE_post_handshake_auth:
return 1;
default:
return 0;
diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
index 0a7bac4d8b..27ff5a5773 100644
--- a/ssl/statem/extensions_srvr.c
+++ b/ssl/statem/extensions_srvr.c
@@ -1161,6 +1161,20 @@ err:
return 0;
}
+int tls_parse_ctos_post_handshake_auth(SSL *s, PACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx)
+{
+ if (PACKET_remaining(pkt) != 0) {
+ SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_POST_HANDSHAKE_AUTH,
+ SSL_R_POST_HANDSHAKE_AUTH_ENCODING_ERR);
+ return 0;
+ }
+
+ s->post_handshake_auth = SSL_PHA_EXT_RECEIVED;
+
+ return 1;
+}
+
/*
* Add the server's renegotiation binding
*/
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index e79bd7b9c0..5050233866 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -1,5 +1,5 @@
/*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
* Copyright 2005 Nokia. All rights reserved.
*
@@ -160,6 +160,26 @@ static int ossl_statem_client13_read_transition(SSL *s, int mt)
st->hand_state = TLS_ST_CR_KEY_UPDATE;
return 1;
}
+ if (mt == SSL3_MT_CERTIFICATE_REQUEST) {
+#if DTLS_MAX_VERSION != DTLS1_2_VERSION
+# error TODO(DTLS1.3): Restore digest for PHA before adding message.
+#endif
+ if (!SSL_IS_DTLS(s) && s->post_handshake_auth == SSL_PHA_EXT_SENT) {
+ s->post_handshake_auth = SSL_PHA_REQUESTED;
+ /*
+ * In TLS, this is called before the message is added to the
+ * digest. In DTLS, this is expected to be called after adding
+ * to the digest. Either move the digest restore, or add the
+ * message here after the swap, or do it after the clientFinished?
+ */
+ if (!tls13_restore_handshake_digest_for_pha(s)) {
+ /* SSLfatal() already called */
+ return 0;
+ }
+ st->hand_state = TLS_ST_CR_CERT_REQ;
+ return 1;
+ }
+ }
break;
}
@@ -375,6 +395,13 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s)
* ossl_statem_client_write_transition().
*/
switch (st->hand_state) {
+ case TLS_ST_CR_CERT_REQ:
+ if (s->post_handshake_auth == SSL_PHA_REQUESTED) {
+ st->hand_state = TLS_ST_CW_CERT;
+ return WRITE_TRAN_CONTINUE;
+ }
+ /* Fall through */
+
default:
/* Shouldn't happen */
SSLfatal(s, SSL_AD_INTERNAL_ERROR,
@@ -798,11 +825,17 @@ WORK_STATE ossl_statem_client_post_work(SSL *s, WORK_STATE wst)
return WORK_MORE_B;
if (SSL_IS_TLS13(s)) {
- if (!s->method->ssl3_enc->change_cipher_state(s,
- SSL3_CC_APPLICATION | SSL3_CHANGE_CIPHER_CLIENT_WRITE)) {
+ if (!tls13_save_handshake_digest_for_pha(s)) {
/* SSLfatal() already called */
return WORK_ERROR;
}
+ if (s->post_handshake_auth != SSL_PHA_REQUESTED) {
+ if (!s->method->ssl3_enc->change_cipher_state(s,
+ SSL3_CC_APPLICATION | SSL3_CHANGE_CIPHER_CLIENT_WRITE)) {
+ /* SSLfatal() already called */
+ return WORK_ERROR;
+ }
+ }
}
break;
@@ -2399,9 +2432,11 @@ MSG_PROCESS_RETURN tls_process_certificate_request(SSL *s, PACKET *pkt)
OPENSSL_free(s->s3->tmp.ctype);
s->s3->tmp.ctype = NULL;
s->s3->tmp.ctype_len = 0;
+ OPENSSL_free(s->pha_context);
+ s->pha_context = NULL;
- /* TODO(TLS1.3) need to process request context, for now ignore */
- if (!PACKET_get_length_prefixed_1(pkt, &reqctx)) {
+ if (!PACKET_get_length_prefixed_1(pkt, &reqctx) ||
+ !PACKET_memdup(&reqctx, &s->pha_context, &s->pha_context_len)) {
SSLfatal(s, SSL_AD_DECODE_ERROR,
SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
SSL_R_LENGTH_MISMATCH);
@@ -3332,6 +3367,7 @@ static int ssl3_check_client_certificate(SSL *s)
if (s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT &&
!tls1_check_chain(s, NULL, NULL, NULL, -2))
return 0;
+
return 1;
}
@@ -3357,8 +3393,12 @@ WORK_STATE tls_prepare_client_certificate(SSL *s, WORK_STATE wst)
}
s->rwstate = SSL_NOTHING;
}
- if (ssl3_check_client_certificate(s))
+ if (ssl3_check_client_certificate(s)) {
+ if (s->post_handshake_auth == SSL_PHA_REQUESTED) {
+ return WORK_FINISHED_STOP;
+ }
return WORK_FINISHED_CONTINUE;
+ }
/* Fall through to WORK_MORE_B */
wst = WORK_MORE_B;
@@ -3403,6 +3443,8 @@ WORK_STATE tls_prepare_client_certificate(SSL *s, WORK_STATE wst)
}
}
+ if (s->post_handshake_auth == SSL_PHA_REQUESTED)
+ return WORK_FINISHED_STOP;
return WORK_FINISHED_CONTINUE;
}
@@ -3414,14 +3456,19 @@ WORK_STATE tls_prepare_client_certificate(SSL *s, WORK_STATE wst)
int tls_construct_client_certificate(SSL *s, WPACKET *pkt)
{
- /*
- * TODO(TLS1.3): For now we must put an empty context. Needs to be filled in
- * later
- */
- if (SSL_IS_TLS13(s) && !WPACKET_put_bytes_u8(pkt, 0)) {
- SSLfatal(s, SSL_AD_INTERNAL_ERROR,
- SSL_F_TLS_CONSTRUCT_CLIENT_CERTIFICATE, ERR_R_INTERNAL_ERROR);
- return 0;
+ if (SSL_IS_TLS13(s)) {
+ if (s->pha_context == NULL) {
+ /* no context available, add 0-length context */
+ if (!WPACKET_put_bytes_u8(pkt, 0)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_CONSTRUCT_CLIENT_CERTIFICATE, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ } else if (!WPACKET_sub_memcpy_u8(pkt, s->pha_context, s->pha_context_len)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_CONSTRUCT_CLIENT_CERTIFICATE, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
}
if (!ssl3_output_cert_chain(s, pkt,
(s->s3->tmp.cert_req == 2) ? NULL
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index 87ce280847..f57f33c4a5 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -1,5 +1,5 @@
/*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
*
* Licensed under the OpenSSL license (the "License"). You may not use
@@ -43,12 +43,15 @@ int ssl3_do_write(SSL *s, int type)
/*
* should not be done for 'Hello Request's, but in that case we'll
* ignore the result anyway
+ * TLS1.3 KeyUpdate and NewSessionTicket do not need to be added
*/
- if (!ssl3_finish_mac(s,
- (unsigned char *)&s->init_buf->data[s->init_off],
- written))
- return -1;
-
+ if (!SSL_IS_TLS13(s) || (s->statem.hand_state != TLS_ST_SW_SESSION_TICKET
+ && s->statem.hand_state != TLS_ST_CW_KEY_UPDATE
+ && s->statem.hand_state != TLS_ST_SW_KEY_UPDATE))
+ if (!ssl3_finish_mac(s,
+ (unsigned char *)&s->init_buf->data[s->init_off],
+ written))
+ return -1;
if (written == s->init_num) {
if (s->msg_callback)
s->msg_callback(1, s->version, type, s->init_buf->data,
@@ -504,7 +507,7 @@ int tls_construct_finished(SSL *s, WPACKET *pkt)
size_t slen;
/* This is a real handshake so make sure we clean it up at the end */
- if (!s->server)
+ if (!s->server && s->post_handshake_auth != SSL_PHA_REQUESTED)
s->statem.cleanuphand = 1;
/*
@@ -741,8 +744,14 @@ MSG_PROCESS_RETURN tls_process_finished(SSL *s, PACKET *pkt)
/* This is a real handshake so make sure we clean it up at the end */
- if (s->server)
- s->statem.cleanuphand = 1;
+ if (s->server) {
+ if (s->post_handshake_auth != SSL_PHA_REQUESTED)
+ s->statem.cleanuphand = 1;
+ if (SSL_IS_TLS13(s) && !tls13_save_handshake_digest_for_pha(s)) {
+ /* SSLfatal() already called */
+ return MSG_PROCESS_ERROR;
+ }
+ }
/*
* In TLSv1.3 a Finished message signals a key change so the end of the
@@ -801,7 +810,8 @@ MSG_PROCESS_RETURN tls_process_finished(SSL *s, PACKET *pkt)
*/
if (SSL_IS_TLS13(s)) {
if (s->server) {
- if (!s->method->ssl3_enc->change_cipher_state(s,
+ if (s->post_handshake_auth != SSL_PHA_REQUESTED &&
+ !s->method->ssl3_enc->change_cipher_state(s,
SSL3_CC_APPLICATION | SSL3_CHANGE_CIPHER_SERVER_READ)) {
/* SSLfatal() already called */
return MSG_PROCESS_ERROR;
@@ -1021,6 +1031,10 @@ WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst, int clearbufs, int stop)
s->init_num = 0;
}
+ if (SSL_IS_TLS13(s) && !s->server
+ && s->post_handshake_auth == SSL_PHA_REQUESTED)
+ s->post_handshake_auth = SSL_PHA_EXT_SENT;
+
if (s->statem.cleanuphand) {
/* skipped if we just sent a HelloRequest */
s->renegotiate = 0;
@@ -1237,18 +1251,24 @@ int tls_get_message_body(SSL *s, size_t *len)
/*
* We defer feeding in the HRR until later. We'll do it as part of
* processing the message
+ * The TLsv1.3 handshake transcript stops at the ClientFinished
+ * message.
*/
#define SERVER_HELLO_RANDOM_OFFSET (SSL3_HM_HEADER_LENGTH + 2)
- if (s->s3->tmp.message_type != SSL3_MT_SERVER_HELLO
- || s->init_num < SERVER_HELLO_RANDOM_OFFSET + SSL3_RANDOM_SIZE
- || memcmp(hrrrandom,
- s->init_buf->data + SERVER_HELLO_RANDOM_OFFSET,
- SSL3_RANDOM_SIZE) != 0) {
- if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
- s->init_num + SSL3_HM_HEADER_LENGTH)) {
- /* SSLfatal() already called */
- *len = 0;
- return 0;
+ /* KeyUpdate and NewSessionTicket do not need to be added */
+ if (!SSL_IS_TLS13(s) || (s->s3->tmp.message_type != SSL3_MT_NEWSESSION_TICKET
+ && s->s3->tmp.message_type != SSL3_MT_KEY_UPDATE)) {
+ if (s->s3->tmp.message_type != SSL3_MT_SERVER_HELLO
+ || s->init_num < SERVER_HELLO_RANDOM_OFFSET + SSL3_RANDOM_SIZE
+ || memcmp(hrrrandom,
+ s->init_buf->data + SERVER_HELLO_RANDOM_OFFSET,
+ SSL3_RANDOM_SIZE) != 0) {
+ if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
+ s->init_num + SSL3_HM_HEADER_LENGTH)) {
+ /* SSLfatal() already called */
+ *len = 0;
+ return 0;
+ }
}
}
if (s->msg_callback)
@@ -2208,3 +2228,54 @@ size_t construct_key_exchange_tbs(SSL *s, unsigned char **ptbs,
*ptbs = tbs;
return tbslen;
}
+
+/*
+ * Saves the current handshake digest for Post-Handshake Auth,
+ * Done after ClientFinished is processed, done exactly once
+ */
+int tls13_save_handshake_digest_for_pha(SSL *s)
+{
+ if (s->pha_dgst == NULL) {
+ if (!ssl3_digest_cached_records(s, 1))
+ /* SSLfatal() already called */
+ return 0;
+
+ s->pha_dgst = EVP_MD_CTX_new();
+ if (s->pha_dgst == NULL) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS13_SAVE_HANDSHAKE_DIGEST_FOR_PHA,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ if (!EVP_MD_CTX_copy_ex(s->pha_dgst,
+ s->s3->handshake_dgst)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS13_SAVE_HANDSHAKE_DIGEST_FOR_PHA,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*
+ * Restores the Post-Handshake Auth handshake digest
+ * Done just before sending/processing the Cert Request
+ */
+int tls13_restore_handshake_digest_for_pha(SSL *s)
+{
+ if (s->pha_dgst == NULL) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS13_RESTORE_HANDSHAKE_DIGEST_FOR_PHA,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ if (!EVP_MD_CTX_copy_ex(s->s3->handshake_dgst,
+ s->pha_dgst)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS13_RESTORE_HANDSHAKE_DIGEST_FOR_PHA,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ return 1;
+}
diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h
index f16d3cba4e..af081ebccc 100644
--- a/ssl/statem/statem_locl.h
+++ b/ssl/statem/statem_locl.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2017 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
@@ -235,6 +235,8 @@ int tls_parse_ctos_psk_kex_modes(SSL *s, PACKET *pkt, unsigned int context,
X509 *x, size_t chainidx);
int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
size_t chainidx);
+int tls_parse_ctos_post_handshake_auth(SSL *, PACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx);
EXT_RETURN tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt,
unsigned int context, X509 *x,
@@ -365,6 +367,9 @@ EXT_RETURN tls_construct_ctos_padding(SSL *s, WPACKET *pkt,
size_t chainidx);
EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context,
X509 *x, size_t chainidx);
+EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL *s, WPACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx);
+
int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, unsigned int context,
X509 *x, size_t chainidx);
int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, unsigned int context,
@@ -411,3 +416,6 @@ int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
size_t chainidx);
int tls_handle_alpn(SSL *s);
+
+int tls13_save_handshake_digest_for_pha(SSL *s);
+int tls13_restore_handshake_digest_for_pha(SSL *s);
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 51b6ce91bc..812780a416 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -1,5 +1,5 @@
/*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
* Copyright 2005 Nokia. All rights reserved.
*
@@ -107,6 +107,13 @@ static int ossl_statem_server13_read_transition(SSL *s, int mt)
*/
if (s->early_data_state == SSL_EARLY_DATA_READING)
break;
+
+ if (mt == SSL3_MT_CERTIFICATE
+ && s->post_handshake_auth == SSL_PHA_REQUESTED) {
+ st->hand_state = TLS_ST_SR_CERT;
+ return 1;
+ }
+
if (mt == SSL3_MT_KEY_UPDATE) {
st->hand_state = TLS_ST_SR_KEY_UPDATE;
return 1;
@@ -325,16 +332,22 @@ static int send_server_key_exchange(SSL *s)
* 1: Yes
* 0: No
*/
-static int send_certificate_request(SSL *s)
+int send_certificate_request(SSL *s)
{
if (
/* don't request cert unless asked for it: */
s->verify_mode & SSL_VERIFY_PEER
/*
+ * don't request if post-handshake-only unless doing
+ * post-handshake in TLSv1.3:
+ */
+ && (!SSL_IS_TLS13(s) || !(s->verify_mode & SSL_VERIFY_POST_HANDSHAKE)
+ || s->post_handshake_auth == SSL_PHA_REQUEST_PENDING)
+ /*
* if SSL_VERIFY_CLIENT_ONCE is set, don't request cert
- * during re-negotiation:
+ * a second time:
*/
- && (s->s3->tmp.finish_md_len == 0 ||
+ && (s->certreqs_sent < 1 ||
!(s->verify_mode & SSL_VERIFY_CLIENT_ONCE))
/*
* never request cert in anonymous ciphersuites (see
@@ -388,6 +401,10 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s)
st->hand_state = TLS_ST_SW_KEY_UPDATE;
return WRITE_TRAN_CONTINUE;
}
+ if (s->post_handshake_auth == SSL_PHA_REQUEST_PENDING) {
+ st->hand_state = TLS_ST_SW_CERT_REQ;
+ return WRITE_TRAN_CONTINUE;
+ }
/* Try to read from the client instead */
return WRITE_TRAN_FINISHED;
@@ -423,7 +440,12 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s)
return WRITE_TRAN_CONTINUE;
case TLS_ST_SW_CERT_REQ:
- st->hand_state = TLS_ST_SW_CERT;
+ if (s->post_handshake_auth == SSL_PHA_REQUEST_PENDING) {
+ s->post_handshake_auth = SSL_PHA_REQUESTED;
+ st->hand_state = TLS_ST_OK;
+ } else {
+ st->hand_state = TLS_ST_SW_CERT;
+ }
return WRITE_TRAN_CONTINUE;
case TLS_ST_SW_CERT:
@@ -450,6 +472,8 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s)
* and give the application the opportunity to delay sending the
* session ticket?
*/
+ if (s->post_handshake_auth == SSL_PHA_REQUESTED)
+ s->post_handshake_auth = SSL_PHA_EXT_RECEIVED;
st->hand_state = TLS_ST_SW_SESSION_TICKET;
return WRITE_TRAN_CONTINUE;
@@ -863,6 +887,13 @@ WORK_STATE ossl_statem_server_post_work(SSL *s, WORK_STATE wst)
}
break;
+ case TLS_ST_SW_CERT_REQ:
+ if (s->post_handshake_auth == SSL_PHA_REQUEST_PENDING) {
+ if (statem_flush(s) != 1)
+ return WORK_MORE_A;
+ }
+ break;
+
case TLS_ST_SW_KEY_UPDATE:
if (statem_flush(s) != 1)
return WORK_MORE_A;
@@ -2702,12 +2733,30 @@ int tls_construct_server_key_exchange(SSL *s, WPACKET *pkt)
int tls_construct_certificate_request(SSL *s, WPACKET *pkt)
{
if (SSL_IS_TLS13(s)) {
- /* TODO(TLS1.3) for now send empty request context */
- if (!WPACKET_put_bytes_u8(pkt, 0)) {
- SSLfatal(s, SSL_AD_INTERNAL_ERROR,
- SSL_F_TLS_CONSTRUCT_CERTIFICATE_REQUEST,
- ERR_R_INTERNAL_ERROR);
- return 0;
+ /*