Add TLSv1.3 post-handshake authentication (PHA)

Add SSL_verify_client_post_handshake() for servers to initiate PHA

Add SSL_force_post_handshake_auth() for clients that don't have certificates
initially configured, but use a certificate callback.

Update SSL_CTX_set_verify()/SSL_set_verify() mode:

* Add SSL_VERIFY_POST_HANDSHAKE to postpone client authentication until after
the initial handshake.

* Update SSL_VERIFY_CLIENT_ONCE now only sends out one CertRequest regardless
of when the certificate authentication takes place; either initial handshake,
re-negotiation, or post-handshake authentication.

Add 'RequestPostHandshake' and 'RequirePostHandshake' SSL_CONF options that
add the SSL_VERIFY_POST_HANDSHAKE to the 'Request' and 'Require' options

Add support to s_client:
* Enabled automatically when cert is configured
* Can be forced enabled via -force_pha

Add support to s_server:
* Use 'c' to invoke PHA in s_server
* Remove some dead code

Update documentation

Update unit tests:
* Illegal use of PHA extension
* TLSv1.3 certificate tests

DTLS and TLS behave ever-so-slightly differently. So, when DTLS1.3 is
implemented, it's PHA support state machine may need to be different.
Add a TODO and a #error

Update handshake context to deal with PHA.

The handshake context for TLSv1.3 post-handshake auth is up through the
ClientFinish message, plus the CertificateRequest message. Subsequent
Certificate, CertificateVerify, and Finish messages are based on this
handshake context (not the Certificate message per se, but it's included
after the hash). KeyUpdate, NewSessionTicket, and prior Certificate
Request messages are not included in post-handshake authentication.

After the ClientFinished message is processed, save off the digest state
for future post-handshake authentication. When post-handshake auth occurs,
copy over the saved handshake context into the "main" handshake digest.
This effectively discards the any KeyUpdate or NewSessionTicket messages
and any prior post-handshake authentication.

This, of course, assumes that the ID-22 did not mean to include any
previous post-handshake authentication into the new handshake transcript.
This is implied by section 4.4.1 that lists messages only up to the
first ClientFinished.

Reviewed-by: Ben Kaduk <kaduk@mit.edu>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/4964)
This commit is contained in:
Todd Short 2017-12-18 16:52:28 -05:00 committed by Matt Caswell
parent 633a8829ff
commit 9d75dce3e1
35 changed files with 1485 additions and 78 deletions

View file

@ -666,6 +666,7 @@ static STRINT_PAIR tlsext_types[] = {
{"psk", TLSEXT_TYPE_psk},
{"psk kex modes", TLSEXT_TYPE_psk_kex_modes},
{"certificate authorities", TLSEXT_TYPE_certificate_authorities},
{"post handshake auth", TLSEXT_TYPE_post_handshake_auth},
{NULL}
};

View file

@ -602,6 +602,7 @@ typedef enum OPTION_choice {
OPT_CT, OPT_NOCT, OPT_CTLOG_FILE,
#endif
OPT_DANE_TLSA_RRDATA, OPT_DANE_EE_NO_NAME,
OPT_FORCE_PHA,
OPT_R_ENUM
} OPTION_CHOICE;
@ -788,6 +789,7 @@ const OPTIONS s_client_options[] = {
#endif
{"keylogfile", OPT_KEYLOG_FILE, '>', "Write TLS secrets to file"},
{"early_data", OPT_EARLY_DATA, '<', "File to send as early data"},
{"force_pha", OPT_FORCE_PHA, '-', "Force-enable post-handshake-authentication"},
{NULL, OPT_EOF, 0x00, NULL}
};
@ -958,6 +960,7 @@ int s_client_main(int argc, char **argv)
int isdtls = 0;
#endif
char *psksessf = NULL;
int force_pha = 0;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
@ -1469,6 +1472,9 @@ int s_client_main(int argc, char **argv)
case OPT_EARLY_DATA:
early_data_file = opt_arg();
break;
case OPT_FORCE_PHA:
force_pha = 1;
break;
}
}
if (count4or6 >= 2) {
@ -1904,6 +1910,9 @@ int s_client_main(int argc, char **argv)
if (con == NULL)
goto end;
if (force_pha)
SSL_force_post_handshake_auth(con);
if (sess_in != NULL) {
SSL_SESSION *sess;
BIO *stmp = BIO_new_file(sess_in, "r");

View file

@ -2501,6 +2501,19 @@ static int sv_body(int s, int stype, int prot, unsigned char *context)
i = 0;
continue;
}
if (buf[0] == 'c' && ((buf[1] == '\n') || (buf[1] == '\r'))) {
SSL_set_verify(con, SSL_VERIFY_PEER, NULL);
i = SSL_verify_client_post_handshake(con);
if (i == 0) {
printf("Failed to initiate request\n");
ERR_print_errors(bio_err);
} else {
i = SSL_do_handshake(con);
printf("SSL_do_handshake -> %d\n", i);
i = 0;
}
continue;
}
if (buf[0] == 'P') {
static const char *str = "Lets print some clear text\n";
BIO_write(SSL_get_wbio(con), str, strlen(str));

View file

@ -1,4 +1,4 @@
# Copyright 1999-2017 The OpenSSL Project Authors. All Rights Reserved.
# Copyright 1999-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
@ -1192,6 +1192,7 @@ SSL_F_SSL_USE_RSAPRIVATEKEY_ASN1:205:SSL_use_RSAPrivateKey_ASN1
SSL_F_SSL_USE_RSAPRIVATEKEY_FILE:206:SSL_use_RSAPrivateKey_file
SSL_F_SSL_VALIDATE_CT:400:ssl_validate_ct
SSL_F_SSL_VERIFY_CERT_CHAIN:207:ssl_verify_cert_chain
SSL_F_SSL_VERIFY_CLIENT_POST_HANDSHAKE:616:SSL_verify_client_post_handshake
SSL_F_SSL_WRITE:208:SSL_write
SSL_F_SSL_WRITE_EARLY_DATA:526:SSL_write_early_data
SSL_F_SSL_WRITE_EARLY_FINISH:527:*
@ -1205,6 +1206,10 @@ SSL_F_TLS13_ENC:609:tls13_enc
SSL_F_TLS13_FINAL_FINISH_MAC:605:tls13_final_finish_mac
SSL_F_TLS13_GENERATE_SECRET:591:tls13_generate_secret
SSL_F_TLS13_HKDF_EXPAND:561:tls13_hkdf_expand
SSL_F_TLS13_RESTORE_HANDSHAKE_DIGEST_FOR_PHA:617:\
tls13_restore_handshake_digest_for_pha
SSL_F_TLS13_SAVE_HANDSHAKE_DIGEST_FOR_PHA:618:\
tls13_save_handshake_digest_for_pha
SSL_F_TLS13_SETUP_KEY_BLOCK:441:tls13_setup_key_block
SSL_F_TLS1_CHANGE_CIPHER_STATE:209:tls1_change_cipher_state
SSL_F_TLS1_CHECK_DUPLICATE_EXTENSIONS:341:*
@ -1247,6 +1252,8 @@ SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE:470:tls_construct_ctos_key_share
SSL_F_TLS_CONSTRUCT_CTOS_MAXFRAGMENTLEN:549:tls_construct_ctos_maxfragmentlen
SSL_F_TLS_CONSTRUCT_CTOS_NPN:471:tls_construct_ctos_npn
SSL_F_TLS_CONSTRUCT_CTOS_PADDING:472:tls_construct_ctos_padding
SSL_F_TLS_CONSTRUCT_CTOS_POST_HANDSHAKE_AUTH:619:\
tls_construct_ctos_post_handshake_auth
SSL_F_TLS_CONSTRUCT_CTOS_PSK:501:tls_construct_ctos_psk
SSL_F_TLS_CONSTRUCT_CTOS_PSK_KEX_MODES:509:tls_construct_ctos_psk_kex_modes
SSL_F_TLS_CONSTRUCT_CTOS_RENEGOTIATE:473:tls_construct_ctos_renegotiate
@ -1315,6 +1322,7 @@ SSL_F_TLS_PARSE_CTOS_EC_PT_FORMATS:569:tls_parse_ctos_ec_pt_formats
SSL_F_TLS_PARSE_CTOS_EMS:570:tls_parse_ctos_ems
SSL_F_TLS_PARSE_CTOS_KEY_SHARE:463:tls_parse_ctos_key_share
SSL_F_TLS_PARSE_CTOS_MAXFRAGMENTLEN:571:tls_parse_ctos_maxfragmentlen
SSL_F_TLS_PARSE_CTOS_POST_HANDSHAKE_AUTH:620:tls_parse_ctos_post_handshake_auth
SSL_F_TLS_PARSE_CTOS_PSK:505:tls_parse_ctos_psk
SSL_F_TLS_PARSE_CTOS_PSK_KEX_MODES:572:tls_parse_ctos_psk_kex_modes
SSL_F_TLS_PARSE_CTOS_RENEGOTIATE:464:tls_parse_ctos_renegotiate
@ -2446,6 +2454,7 @@ SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST:151:error in received cipher list
SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN:204:error setting tlsa base domain
SSL_R_EXCEEDS_MAX_FRAGMENT_SIZE:194:exceeds max fragment size
SSL_R_EXCESSIVE_MESSAGE_SIZE:152:excessive message size
SSL_R_EXTENSION_NOT_RECEIVED:279:extension not received
SSL_R_EXTRA_DATA_IN_MESSAGE:153:extra data in message
SSL_R_EXT_LENGTH_MISMATCH:163:ext length mismatch
SSL_R_FAILED_TO_INIT_ASYNC:405:failed to init async
@ -2466,7 +2475,9 @@ SSL_R_INVALID_CCS_MESSAGE:260:invalid ccs message
SSL_R_INVALID_CERTIFICATE_OR_ALG:238:invalid certificate or alg
SSL_R_INVALID_COMMAND:280:invalid command
SSL_R_INVALID_COMPRESSION_ALGORITHM:341:invalid compression algorithm
SSL_R_INVALID_CONFIG:283:invalid config
SSL_R_INVALID_CONFIGURATION_NAME:113:invalid configuration name
SSL_R_INVALID_CONTEXT:282:invalid context
SSL_R_INVALID_CT_VALIDATION_TYPE:212:invalid ct validation type
SSL_R_INVALID_KEY_UPDATE_TYPE:120:invalid key update type
SSL_R_INVALID_MAX_EARLY_DATA:174:invalid max early data
@ -2495,6 +2506,7 @@ SSL_R_MISSING_SUPPORTED_GROUPS_EXTENSION:209:missing supported groups extension
SSL_R_MISSING_TMP_DH_KEY:171:missing tmp dh key
SSL_R_MISSING_TMP_ECDH_KEY:311:missing tmp ecdh key
SSL_R_NOT_ON_RECORD_BOUNDARY:182:not on record boundary
SSL_R_NOT_SERVER:284:not server
SSL_R_NO_APPLICATION_PROTOCOL:235:no application protocol
SSL_R_NO_CERTIFICATES_RETURNED:176:no certificates returned
SSL_R_NO_CERTIFICATE_ASSIGNED:177:no certificate assigned
@ -2534,6 +2546,7 @@ SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE:199:peer did not return a certificate
SSL_R_PEM_NAME_BAD_PREFIX:391:pem name bad prefix
SSL_R_PEM_NAME_TOO_SHORT:392:pem name too short
SSL_R_PIPELINE_FAILURE:406:pipeline failure
SSL_R_POST_HANDSHAKE_AUTH_ENCODING_ERR:278:post handshake auth encoding err
SSL_R_PROTOCOL_IS_SHUTDOWN:207:protocol is shutdown
SSL_R_PSK_IDENTITY_NOT_FOUND:223:psk identity not found
SSL_R_PSK_NO_CLIENT_CB:224:psk no client cb
@ -2545,6 +2558,8 @@ SSL_R_RECORD_TOO_SMALL:298:record too small
SSL_R_RENEGOTIATE_EXT_TOO_LONG:335:renegotiate ext too long
SSL_R_RENEGOTIATION_ENCODING_ERR:336:renegotiation encoding err
SSL_R_RENEGOTIATION_MISMATCH:337:renegotiation mismatch
SSL_R_REQUEST_PENDING:285:request pending
SSL_R_REQUEST_SENT:286:request sent
SSL_R_REQUIRED_CIPHER_MISSING:215:required cipher missing
SSL_R_REQUIRED_COMPRESSION_ALGORITHM_MISSING:342:\
required compression algorithm missing

View file

@ -118,6 +118,7 @@ B<openssl> B<s_client>
[B<-ctlogfile>]
[B<-keylogfile file>]
[B<-early_data file>]
[B<-force_pha>]
[B<target>]
=head1 DESCRIPTION
@ -621,6 +622,11 @@ Reads the contents of the specified file and attempts to send it as early data
to the server. This will only work with resumed sessions that support early
data and when the server accepts the early data.
=item B<-force_pha>
For TLSv1.3 only, always send the Post-Handshake Authentication extension,
whether or not a certificate has been provided via B<-cert>.
=item B<[target]>
Rather than providing B<-connect>, the target hostname and optional port may

View file

@ -435,6 +435,18 @@ occurs if the client does not present a certificate. Servers only.
B<Once> requests a certificate from a client only on the initial connection:
not when renegotiating. Servers only.
B<RequestPostHandshake> configures the connection to support requests but does
not require a certificate from the client post-handshake. A certificate will
not be requested during the initial handshake. The server application must
provide a mechanism to request a certificate post-handshake. Servers only.
TLSv1.3 only.
B<RequiresPostHandshake> configures the connection to support requests and
requires a certificate from the client post-handshake: an error occurs if the
client does not present a certificate. A certificate will not be requested
during the initial handshake. The server application must provide a mechanism
to request a certificate post-handshake. Servers only. TLSv1.3 only.
=item B<ClientCAFile>, B<ClientCAPath>
A file or directory of certificates in PEM format whose names are used as the

View file

@ -5,7 +5,9 @@
SSL_get_ex_data_X509_STORE_CTX_idx,
SSL_CTX_set_verify, SSL_set_verify,
SSL_CTX_set_verify_depth, SSL_set_verify_depth,
SSL_verify_cb
SSL_verify_cb,
SSL_verify_client_post_handshake,
SSL_force_post_handshake_auth
- set peer certificate verification parameters
=head1 SYNOPSIS
@ -15,11 +17,14 @@ SSL_verify_cb
typedef int (*SSL_verify_cb)(int preverify_ok, X509_STORE_CTX *x509_ctx);
void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, SSL_verify_cb verify_callback);
void SSL_set_verify(SSL *s, int mode, SSL_verify_cb verify_callback);
void SSL_set_verify(SSL *ssl, int mode, SSL_verify_cb verify_callback);
SSL_get_ex_data_X509_STORE_CTX_idx(void);
void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth);
void SSL_set_verify_depth(SSL *s, int depth);
void SSL_set_verify_depth(SSL *ssl, int depth);
int SSL_verify_client_post_handshake(SSL *ssl);
void SSL_force_post_handshake_auth(SSL *ssl);
=head1 DESCRIPTION
@ -43,6 +48,16 @@ verification that shall be allowed for B<ctx>.
SSL_set_verify_depth() sets the maximum B<depth> for the certificate chain
verification that shall be allowed for B<ssl>.
SSL_force_post_handshake_auth() forces the Post-Handshake Authentication
extension to be added to the ClientHello regardless of certificate configuration
at the time of the initial handshake, such that post-handshake authentication
can be requested by the server. A certificate callback will need to be set via
SSL_CTX_set_client_cert_cb() if no certificate is provided at initialization.
SSL_verify_client_post_handshake() causes a Certificate Request message to be
sent by a server on the given B<ssl> connection. The SSL_VERIFY_PEER flag must
be set, the SSL_VERIFY_POST_HANDSHAKE flag is optional.
=head1 NOTES
The verification of certificates can be controlled by a set of logically
@ -69,7 +84,8 @@ fails, the TLS/SSL handshake is
immediately terminated with an alert message containing the reason for
the verification failure.
The behaviour can be controlled by the additional
SSL_VERIFY_FAIL_IF_NO_PEER_CERT and SSL_VERIFY_CLIENT_ONCE flags.
SSL_VERIFY_FAIL_IF_NO_PEER_CERT, SSL_VERIFY_CLIENT_ONCE and
SSL_VERIFY_POST_HANDSHAKE flags.
B<Client mode:> the server certificate is verified. If the verification process
fails, the TLS/SSL handshake is
@ -87,9 +103,22 @@ B<Client mode:> ignored
=item SSL_VERIFY_CLIENT_ONCE
B<Server mode:> only request a client certificate on the initial TLS/SSL
handshake. Do not ask for a client certificate again in case of a
renegotiation. This flag must be used together with SSL_VERIFY_PEER.
B<Server mode:> only request a client certificate once during the
connection. Do not ask for a client certificate again during
renegotiation or post-authentication if a certificate was requested
during the initial handshake. This flag must be used together with
SSL_VERIFY_PEER.
B<Client mode:> ignored
=item SSL_VERIFY_POST_HANDSHAKE
B<Server mode:> the server will not send a client certificate request
during the initial handshake, but will send the request via
SSL_verify_client_post_handshake(). This allows the SSL_CTX or SSL
to be configured for post-handshake peer verification before the
handshake occurs. This flag must be used together with
SSL_VERIFY_PEER. TLSv1.3 only; no effect on pre-TLSv1.3 connections.
B<Client mode:> ignored
@ -154,6 +183,20 @@ Its return value is identical to B<preverify_ok>, so that any verification
failure will lead to a termination of the TLS/SSL handshake with an
alert message, if SSL_VERIFY_PEER is set.
After calling SSL_force_post_handshake_auth(), the client will need to add a
certificate to its configuration before it can successfully authenticate. This
must be called before SSL_connect().
SSL_verify_client_post_handshake() requires that verify flags have been
previously set, and that a client sent the post-handshake authentication
extension. When the client returns a certificate the verify callback will be
invoked. A write operation must take place for the Certificate Request to be
sent to the client, this can be done with SSL_do_handshake() or SSL_write_ex().
Only one certificate request may be outstanding at any time.
When post-handshake authentication occurs, a refreshed B<NewSessionTicket>
message is sent to the client.
=head1 BUGS
In client mode, it is not checked whether the SSL_VERIFY_PEER flag
@ -165,6 +208,10 @@ required.
The SSL*_set_verify*() functions do not provide diagnostic information.
The SSL_verify_client_post_handshake() function returns 1 if the request
succeeded, and 0 if the request failed. The error stack can be examined
to determine the failure reason.
=head1 EXAMPLES
The following code sequence realizes an example B<verify_callback> function
@ -288,8 +335,14 @@ L<SSL_CTX_load_verify_locations(3)>,
L<SSL_get_peer_certificate(3)>,
L<SSL_CTX_set_cert_verify_callback(3)>,
L<SSL_get_ex_data_X509_STORE_CTX_idx(3)>,
L<SSL_CTX_set_client_cert_cb(3)>,
L<CRYPTO_get_ex_new_index(3)>
=head1 HISTORY
The SSL_VERIFY_POST_HANDSHAKE option, and the SSL_verify_client_post_handshake()
and SSL_force_post_handshake_auth() functions were added in OpenSSL 1.1.1.
=head1 COPYRIGHT
Copyright 2000-2017 The OpenSSL Project Authors. All Rights Reserved.

View file

@ -1052,13 +1052,14 @@ size_t SSL_get_finished(const SSL *s, void *buf, size_t count);
size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count);
/*
* use either SSL_VERIFY_NONE or SSL_VERIFY_PEER, the last 2 options are
* use either SSL_VERIFY_NONE or SSL_VERIFY_PEER, the last 3 options are
* 'ored' with SSL_VERIFY_PEER if they are desired
*/
# define SSL_VERIFY_NONE 0x00
# define SSL_VERIFY_PEER 0x01
# define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02
# define SSL_VERIFY_CLIENT_ONCE 0x04
# define SSL_VERIFY_POST_HANDSHAKE 0x08
# define OpenSSL_add_ssl_algorithms() SSL_library_init()
# if OPENSSL_API_COMPAT < 0x10100000L
@ -1850,6 +1851,8 @@ int SSL_renegotiate(SSL *s);
int SSL_renegotiate_abbreviated(SSL *s);
__owur int SSL_renegotiate_pending(SSL *s);
int SSL_shutdown(SSL *s);
__owur int SSL_verify_client_post_handshake(SSL *s);
void SSL_force_post_handshake_auth(SSL *s);
__owur const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx);
__owur const SSL_METHOD *SSL_get_ssl_method(SSL *s);

View file

@ -241,6 +241,7 @@ int ERR_load_SSL_strings(void);
# define SSL_F_SSL_USE_RSAPRIVATEKEY_FILE 206
# define SSL_F_SSL_VALIDATE_CT 400
# define SSL_F_SSL_VERIFY_CERT_CHAIN 207
# define SSL_F_SSL_VERIFY_CLIENT_POST_HANDSHAKE 616
# define SSL_F_SSL_WRITE 208
# define SSL_F_SSL_WRITE_EARLY_DATA 526
# define SSL_F_SSL_WRITE_EARLY_FINISH 527
@ -254,6 +255,8 @@ int ERR_load_SSL_strings(void);
# define SSL_F_TLS13_FINAL_FINISH_MAC 605
# define SSL_F_TLS13_GENERATE_SECRET 591
# define SSL_F_TLS13_HKDF_EXPAND 561
# define SSL_F_TLS13_RESTORE_HANDSHAKE_DIGEST_FOR_PHA 617
# define SSL_F_TLS13_SAVE_HANDSHAKE_DIGEST_FOR_PHA 618
# define SSL_F_TLS13_SETUP_KEY_BLOCK 441
# define SSL_F_TLS1_CHANGE_CIPHER_STATE 209
# define SSL_F_TLS1_CHECK_DUPLICATE_EXTENSIONS 341
@ -295,6 +298,7 @@ int ERR_load_SSL_strings(void);
# define SSL_F_TLS_CONSTRUCT_CTOS_MAXFRAGMENTLEN 549
# define SSL_F_TLS_CONSTRUCT_CTOS_NPN 471
# define SSL_F_TLS_CONSTRUCT_CTOS_PADDING 472
# define SSL_F_TLS_CONSTRUCT_CTOS_POST_HANDSHAKE_AUTH 619
# define SSL_F_TLS_CONSTRUCT_CTOS_PSK 501
# define SSL_F_TLS_CONSTRUCT_CTOS_PSK_KEX_MODES 509
# define SSL_F_TLS_CONSTRUCT_CTOS_RENEGOTIATE 473
@ -358,6 +362,7 @@ int ERR_load_SSL_strings(void);
# define SSL_F_TLS_PARSE_CTOS_EMS 570
# define SSL_F_TLS_PARSE_CTOS_KEY_SHARE 463
# define SSL_F_TLS_PARSE_CTOS_MAXFRAGMENTLEN 571
# define SSL_F_TLS_PARSE_CTOS_POST_HANDSHAKE_AUTH 620
# define SSL_F_TLS_PARSE_CTOS_PSK 505
# define SSL_F_TLS_PARSE_CTOS_PSK_KEX_MODES 572
# define SSL_F_TLS_PARSE_CTOS_RENEGOTIATE 464
@ -522,6 +527,7 @@ int ERR_load_SSL_strings(void);
# define SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN 204
# define SSL_R_EXCEEDS_MAX_FRAGMENT_SIZE 194
# define SSL_R_EXCESSIVE_MESSAGE_SIZE 152
# define SSL_R_EXTENSION_NOT_RECEIVED 279
# define SSL_R_EXTRA_DATA_IN_MESSAGE 153
# define SSL_R_EXT_LENGTH_MISMATCH 163
# define SSL_R_FAILED_TO_INIT_ASYNC 405
@ -542,7 +548,9 @@ int ERR_load_SSL_strings(void);
# define SSL_R_INVALID_CERTIFICATE_OR_ALG 238
# define SSL_R_INVALID_COMMAND 280
# define SSL_R_INVALID_COMPRESSION_ALGORITHM 341
# define SSL_R_INVALID_CONFIG 283
# define SSL_R_INVALID_CONFIGURATION_NAME 113
# define SSL_R_INVALID_CONTEXT 282
# define SSL_R_INVALID_CT_VALIDATION_TYPE 212
# define SSL_R_INVALID_KEY_UPDATE_TYPE 120
# define SSL_R_INVALID_MAX_EARLY_DATA 174
@ -571,6 +579,7 @@ int ERR_load_SSL_strings(void);
# define SSL_R_MISSING_TMP_DH_KEY 171
# define SSL_R_MISSING_TMP_ECDH_KEY 311
# define SSL_R_NOT_ON_RECORD_BOUNDARY 182
# define SSL_R_NOT_SERVER 284
# define SSL_R_NO_APPLICATION_PROTOCOL 235
# define SSL_R_NO_CERTIFICATES_RETURNED 176
# define SSL_R_NO_CERTIFICATE_ASSIGNED 177
@ -608,6 +617,7 @@ int ERR_load_SSL_strings(void);
# define SSL_R_PEM_NAME_BAD_PREFIX 391
# define SSL_R_PEM_NAME_TOO_SHORT 392
# define SSL_R_PIPELINE_FAILURE 406
# define SSL_R_POST_HANDSHAKE_AUTH_ENCODING_ERR 278
# define SSL_R_PROTOCOL_IS_SHUTDOWN 207
# define SSL_R_PSK_IDENTITY_NOT_FOUND 223
# define SSL_R_PSK_NO_CLIENT_CB 224
@ -619,6 +629,8 @@ int ERR_load_SSL_strings(void);
# define SSL_R_RENEGOTIATE_EXT_TOO_LONG 335
# define SSL_R_RENEGOTIATION_ENCODING_ERR 336
# define SSL_R_RENEGOTIATION_MISMATCH 337
# define SSL_R_REQUEST_PENDING 285
# define SSL_R_REQUEST_SENT 286
# define SSL_R_REQUIRED_CIPHER_MISSING 215
# define SSL_R_REQUIRED_COMPRESSION_ALGORITHM_MISSING 342
# define SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING 345

View file

@ -146,6 +146,7 @@ extern "C" {
# define TLSEXT_TYPE_cookie 44
# define TLSEXT_TYPE_psk_kex_modes 45
# define TLSEXT_TYPE_certificate_authorities 47
# define TLSEXT_TYPE_post_handshake_auth 49
# define TLSEXT_TYPE_signature_algorithms_cert 50
# define TLSEXT_TYPE_key_share 51

View file

@ -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;

View file

@ -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),

View file

@ -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;
}

View file

@ -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,

View file

@ -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 */
@ -289,6 +291,14 @@ static const EXTENSION_DEFINITION ext_defs[] = {
/* We do not generate signature_algorithms_cert at present. */
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,
@ -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;
}

View file

@ -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
*/

View file

@ -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;

View file

@ -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
*/

View file

@ -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

View file

@ -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;
}

View file

@ -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);

View file

@ -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
/*
* if SSL_VERIFY_CLIENT_ONCE is set, don't request cert
* during re-negotiation:
* don't request if post-handshake-only unless doing
* post-handshake in TLSv1.3:
*/
&& (s->s3->tmp.finish_md_len == 0 ||
&& (!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
* a second time:
*/
&& (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;
/* Send random context when doing post-handshake auth */
if (s->post_handshake_auth == SSL_PHA_REQUEST_PENDING) {
OPENSSL_free(s->pha_context);
s->pha_context_len = 32;
if ((s->pha_context = OPENSSL_malloc(s->pha_context_len)) == NULL
|| ssl_randbytes(s, s->pha_context, s->pha_context_len) <= 0
|| !WPACKET_sub_memcpy_u8(pkt, s->pha_context, s->pha_context_len)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR,
SSL_F_TLS_CONSTRUCT_CERTIFICATE_REQUEST,
ERR_R_INTERNAL_ERROR);
return 0;
}
/* reset the handshake hash back to just after the ClientFinished */
if (!tls13_restore_handshake_digest_for_pha(s)) {
/* SSLfatal() already called */
return 0;
}
} else {
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;
}
}
if (!tls_construct_extensions(s, pkt,
@ -2748,6 +2797,7 @@ int tls_construct_certificate_request(SSL *s, WPACKET *pkt)
}
done:
s->certreqs_sent++;
s->s3->tmp.cert_request = 1;
return 1;
}
@ -3396,11 +3446,12 @@ MSG_PROCESS_RETURN tls_process_client_certificate(SSL *s, PACKET *pkt)
int i;
MSG_PROCESS_RETURN ret = MSG_PROCESS_ERROR;
X509 *x = NULL;
unsigned long l, llen;
unsigned long l;
const unsigned char *certstart, *certbytes;
STACK_OF(X509) *sk = NULL;
PACKET spkt, context;
size_t chainidx;
SSL_SESSION *new_sess = NULL;
if ((sk = sk_X509_new_null()) == NULL) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
@ -3408,10 +3459,16 @@ MSG_PROCESS_RETURN tls_process_client_certificate(SSL *s, PACKET *pkt)
goto err;
}
/* TODO(TLS1.3): For now we ignore the context. We need to verify this */
if ((SSL_IS_TLS13(s) && !PACKET_get_length_prefixed_1(pkt, &context))
|| !PACKET_get_net_3(pkt, &llen)
|| !PACKET_get_sub_packet(pkt, &spkt, llen)
if (SSL_IS_TLS13(s) && (!PACKET_get_length_prefixed_1(pkt, &context)
|| (s->pha_context == NULL && PACKET_remaining(&context) != 0)
|| (s->pha_context != NULL &&
!PACKET_equal(&context, s->pha_context, s->pha_context_len)))) {
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
SSL_R_INVALID_CONTEXT);
goto err;
}
if (!PACKET_get_length_prefixed_3(pkt, &spkt)
|| PACKET_remaining(pkt) != 0) {
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
SSL_R_LENGTH_MISMATCH);
@ -3516,6 +3573,35 @@ MSG_PROCESS_RETURN tls_process_client_certificate(SSL *s, PACKET *pkt)
}
}
/*
* Sessions must be immutable once they go into the session cache. Otherwise
* we can get multi-thread problems. Therefore we don't "update" sessions,
* we replace them with a duplicate. Here, we need to do this every time
* a new certificate is received via post-handshake authentication, as the
* session may have already gone into the session cache.
*/
if (s->post_handshake_auth == SSL_PHA_REQUESTED) {
int m = s->session_ctx->session_cache_mode;
if ((new_sess = ssl_session_dup(s->session, 0)) == 0) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR,
SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
ERR_R_MALLOC_FAILURE);
goto err;
}
if (m & SSL_SESS_CACHE_SERVER) {
/*
* Remove the old session from the cache. We carry on if this fails
*/
SSL_CTX_remove_session(s->session_ctx, s->session);
}
SSL_SESSION_free(s->session);
s->session = new_sess;
}
X509_free(s->session->peer);
s->session->peer = sk_X509_shift(sk);
s->session->verify_result = s->verify_result;
@ -3523,6 +3609,9 @@ MSG_PROCESS_RETURN tls_process_client_certificate(SSL *s, PACKET *pkt)
sk_X509_pop_free(s->session->peer_chain, X509_free);
s->session->peer_chain = sk;
if (new_sess != NULL)
ssl_update_cache(s, SSL_SESS_CACHE_SERVER);
/*
* Freeze the handshake buffer. For <TLS1.3 we do this after the CKE
* message

View file

@ -481,7 +481,8 @@ static const ssl_trace_tbl ssl_exts_tbl[] = {
{TLSEXT_TYPE_padding, "padding"},
{TLSEXT_TYPE_encrypt_then_mac, "encrypt_then_mac"},
{TLSEXT_TYPE_extended_master_secret, "extended_master_secret"},
{TLSEXT_TYPE_early_data, "early_data"}
{TLSEXT_TYPE_early_data, "early_data"},
{TLSEXT_TYPE_post_handshake_auth, "post_handshake_auth"}
};
static const ssl_trace_tbl ssl_groups_tbl[] = {

View file

@ -268,7 +268,7 @@ INCLUDE_MAIN___test_libtestutil_OLB = /INCLUDE=MAIN
DEPEND[cipherlist_test]=../libcrypto ../libssl libtestutil.a
INCLUDE[ssl_test_ctx.o]=../include
INCLUDE[handshake_helper.o]=../include
INCLUDE[handshake_helper.o]=.. ../include
INCLUDE[ssltestlib.o]=.. ../include
SOURCE[x509aux]=x509aux.c

View file

@ -16,6 +16,7 @@
#include <openssl/srp.h>
#endif
#include "../ssl/ssl_locl.h"
#include "internal/sockets.h"
#include "internal/nelem.h"
#include "handshake_helper.h"
@ -674,6 +675,8 @@ static void configure_handshake_ssl(SSL *server, SSL *client,
if (extra->client.servername != SSL_TEST_SERVERNAME_NONE)
SSL_set_tlsext_host_name(client,
ssl_servername_name(extra->client.servername));
if (extra->client.force_pha)
SSL_force_post_handshake_auth(client);
}
/* The status for each connection phase. */
@ -848,7 +851,9 @@ static void do_reneg_setup_step(const SSL_TEST_CTX *test_ctx, PEER *peer)
|| test_ctx->handshake_mode
== SSL_TEST_HANDSHAKE_KEY_UPDATE_SERVER
|| test_ctx->handshake_mode
== SSL_TEST_HANDSHAKE_KEY_UPDATE_CLIENT)) {
== SSL_TEST_HANDSHAKE_KEY_UPDATE_CLIENT
|| test_ctx->handshake_mode
== SSL_TEST_HANDSHAKE_POST_HANDSHAKE_AUTH)) {
peer->status = PEER_TEST_FAILURE;
return;
}
@ -929,6 +934,25 @@ static void do_reneg_setup_step(const SSL_TEST_CTX *test_ctx, PEER *peer)
if (peer->status != PEER_SUCCESS)
peer->status = PEER_ERROR;
return;
} else if (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_POST_HANDSHAKE_AUTH) {
if (SSL_is_server(peer->ssl)) {
/* Make the server believe it's received the extension */
if (test_ctx->extra.server.force_pha)
peer->ssl->post_handshake_auth = SSL_PHA_EXT_RECEIVED;
ret = SSL_verify_client_post_handshake(peer->ssl);
if (!ret) {
peer->status = PEER_ERROR;
return;
}
}
do_handshake_step(peer);
/*
* This is a one step handshake. We shouldn't get anything other than
* PEER_SUCCESS
*/
if (peer->status != PEER_SUCCESS)
peer->status = PEER_ERROR;
return;
}
/*
@ -1004,25 +1028,41 @@ typedef enum {
CONNECTION_DONE
} connect_phase_t;
static int renegotiate_op(const SSL_TEST_CTX *test_ctx)
{
switch (test_ctx->handshake_mode) {
case SSL_TEST_HANDSHAKE_RENEG_SERVER:
case SSL_TEST_HANDSHAKE_RENEG_CLIENT:
return 1;
default:
return 0;
}
}
static int post_handshake_op(const SSL_TEST_CTX *test_ctx)
{
switch (test_ctx->handshake_mode) {
case SSL_TEST_HANDSHAKE_KEY_UPDATE_CLIENT:
case SSL_TEST_HANDSHAKE_KEY_UPDATE_SERVER:
case SSL_TEST_HANDSHAKE_POST_HANDSHAKE_AUTH:
return 1;
default:
return 0;
}
}
static connect_phase_t next_phase(const SSL_TEST_CTX *test_ctx,
connect_phase_t phase)
{
switch (phase) {
case HANDSHAKE:
if (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_SERVER
|| test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_CLIENT
|| test_ctx->handshake_mode
== SSL_TEST_HANDSHAKE_KEY_UPDATE_CLIENT
|| test_ctx->handshake_mode
== SSL_TEST_HANDSHAKE_KEY_UPDATE_SERVER)
if (renegotiate_op(test_ctx) || post_handshake_op(test_ctx))
return RENEG_APPLICATION_DATA;
return APPLICATION_DATA;
case RENEG_APPLICATION_DATA:
return RENEG_SETUP;
case RENEG_SETUP:
if (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_KEY_UPDATE_SERVER
|| test_ctx->handshake_mode
== SSL_TEST_HANDSHAKE_KEY_UPDATE_CLIENT)
if (post_handshake_op(test_ctx))
return APPLICATION_DATA;
return RENEG_HANDSHAKE;
case RENEG_HANDSHAKE:

View file

@ -89,6 +89,8 @@ $ENV{CTLOG_FILE} = srctop_file("test", "ct", "log_list.conf");
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK,
checkhandshake::PSK_CLI_EXTENSION],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_POST_HANDSHAKE_AUTH,
checkhandshake::POST_HANDSHAKE_AUTH_CLI_EXTENSION],
[TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_SUPPORTED_VERSIONS,
checkhandshake::DEFAULT_EXTENSIONS],
@ -123,6 +125,8 @@ $ENV{CTLOG_FILE} = srctop_file("test", "ct", "log_list.conf");
checkhandshake::DEFAULT_EXTENSIONS],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK,
checkhandshake::PSK_CLI_EXTENSION],
[TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_POST_HANDSHAKE_AUTH,
checkhandshake::POST_HANDSHAKE_AUTH_CLI_EXTENSION],
[TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_SUPPORTED_VERSIONS,
checkhandshake::DEFAULT_EXTENSIONS],
@ -214,7 +218,8 @@ $proxy->clientflags("-cert ".srctop_file("apps", "server.pem"));
$proxy->serverflags("-Verify 5");
$proxy->start();
checkhandshake($proxy, checkhandshake::CLIENT_AUTH_HANDSHAKE,
checkhandshake::DEFAULT_EXTENSIONS,
checkhandshake::DEFAULT_EXTENSIONS |
checkhandshake::POST_HANDSHAKE_AUTH_CLI_EXTENSION,
"Client auth handshake test");
#Test 7: Server name handshake (no client request)

View file

@ -28,7 +28,7 @@ map { s/\^// } @conf_files if $^O eq "VMS";
# We hard-code the number of tests to double-check that the globbing above
# finds all files as expected.
plan tests => 25; # = scalar @conf_srcs
plan tests => 26; # = scalar @conf_srcs
# Some test results depend on the configuration of enabled protocols. We only
# verify generated sources in the default configuration.
@ -96,6 +96,7 @@ my %skip = (
&& disabled("tls1_2")) || disabled("srp"),
"24-padding.conf" => disabled("tls1_3"),
"25-cipher.conf" => disabled("ec") || disabled("tls1_2"),
"26-tls13_client_auth.conf" => disabled("tls1_3"),
);
foreach my $conf (@conf_files) {

View file

@ -0,0 +1,476 @@
# Generated with generate_ssl_tests.pl
num_tests = 14
test-0 = 0-server-auth-TLSv1.3
test-1 = 1-client-auth-TLSv1.3-request
test-2 = 2-client-auth-TLSv1.3-require-fail
test-3 = 3-client-auth-TLSv1.3-require
test-4 = 4-client-auth-TLSv1.3-require-non-empty-names
test-5 = 5-client-auth-TLSv1.3-noroot
test-6 = 6-client-auth-TLSv1.3-request-post-handshake
test-7 = 7-client-auth-TLSv1.3-require-fail-post-handshake
test-8 = 8-client-auth-TLSv1.3-require-post-handshake
test-9 = 9-client-auth-TLSv1.3-require-non-empty-names-post-handshake
test-10 = 10-client-auth-TLSv1.3-noroot-post-handshake
test-11 = 11-client-auth-TLSv1.3-request-force-client-post-handshake
test-12 = 12-client-auth-TLSv1.3-request-force-server-post-handshake
test-13 = 13-client-auth-TLSv1.3-request-force-both-post-handshake
# ===========================================================
[0-server-auth-TLSv1.3]
ssl_conf = 0-server-auth-TLSv1.3-ssl
[0-server-auth-TLSv1.3-ssl]
server = 0-server-auth-TLSv1.3-server
client = 0-server-auth-TLSv1.3-client
[0-server-auth-TLSv1.3-server]
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
[0-server-auth-TLSv1.3-client]
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
VerifyMode = Peer
[test-0]
ExpectedResult = Success
# ===========================================================
[1-client-auth-TLSv1.3-request]
ssl_conf = 1-client-auth-TLSv1.3-request-ssl
[1-client-auth-TLSv1.3-request-ssl]
server = 1-client-auth-TLSv1.3-request-server
client = 1-client-auth-TLSv1.3-request-client
[1-client-auth-TLSv1.3-request-server]
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
VerifyMode = Request
[1-client-auth-TLSv1.3-request-client]
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
VerifyMode = Peer
[test-1]
ExpectedResult = Success
# ===========================================================
[2-client-auth-TLSv1.3-require-fail]
ssl_conf = 2-client-auth-TLSv1.3-require-fail-ssl
[2-client-auth-TLSv1.3-require-fail-ssl]
server = 2-client-auth-TLSv1.3-require-fail-server
client = 2-client-auth-TLSv1.3-require-fail-client
[2-client-auth-TLSv1.3-require-fail-server]
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/root-cert.pem
VerifyMode = Require
[2-client-auth-TLSv1.3-require-fail-client]
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
VerifyMode = Peer
[test-2]
ExpectedResult = ServerFail
ExpectedServerAlert = HandshakeFailure
# ===========================================================
[3-client-auth-TLSv1.3-require]
ssl_conf = 3-client-auth-TLSv1.3-require-ssl
[3-client-auth-TLSv1.3-require-ssl]
server = 3-client-auth-TLSv1.3-require-server
client = 3-client-auth-TLSv1.3-require-client
[3-client-auth-TLSv1.3-require-server]
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
CipherString = DEFAULT
ClientSignatureAlgorithms = PSS+SHA256
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/root-cert.pem
VerifyMode = Request
[3-client-auth-TLSv1.3-require-client]
Certificate = ${ENV::TEST_CERTS_DIR}/ee-client-chain.pem
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
PrivateKey = ${ENV::TEST_CERTS_DIR}/ee-key.pem
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
VerifyMode = Peer
[test-3]
ExpectedClientCANames = empty
ExpectedClientCertType = RSA
ExpectedClientSignHash = SHA256
ExpectedClientSignType = RSA-PSS
ExpectedResult = Success
# ===========================================================
[4-client-auth-TLSv1.3-require-non-empty-names]
ssl_conf = 4-client-auth-TLSv1.3-require-non-empty-names-ssl
[4-client-auth-TLSv1.3-require-non-empty-names-ssl]
server = 4-client-auth-TLSv1.3-require-non-empty-names-server
client = 4-client-auth-TLSv1.3-require-non-empty-names-client
[4-client-auth-TLSv1.3-require-non-empty-names-server]
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
CipherString = DEFAULT
ClientCAFile = ${ENV::TEST_CERTS_DIR}/root-cert.pem
ClientSignatureAlgorithms = PSS+SHA256
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/root-cert.pem
VerifyMode = Request
[4-client-auth-TLSv1.3-require-non-empty-names-client]
Certificate = ${ENV::TEST_CERTS_DIR}/ee-client-chain.pem
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
PrivateKey = ${ENV::TEST_CERTS_DIR}/ee-key.pem
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
VerifyMode = Peer
[test-4]
ExpectedClientCANames = ${ENV::TEST_CERTS_DIR}/root-cert.pem
ExpectedClientCertType = RSA
ExpectedClientSignHash = SHA256
ExpectedClientSignType = RSA-PSS
ExpectedResult = Success
# ===========================================================
[5-client-auth-TLSv1.3-noroot]
ssl_conf = 5-client-auth-TLSv1.3-noroot-ssl
[5-client-auth-TLSv1.3-noroot-ssl]
server = 5-client-auth-TLSv1.3-noroot-server
client = 5-client-auth-TLSv1.3-noroot-client
[5-client-auth-TLSv1.3-noroot-server]
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
VerifyMode = Require
[5-client-auth-TLSv1.3-noroot-client]
Certificate = ${ENV::TEST_CERTS_DIR}/ee-client-chain.pem
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
PrivateKey = ${ENV::TEST_CERTS_DIR}/ee-key.pem
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
VerifyMode = Peer
[test-5]
ExpectedResult = ServerFail
ExpectedServerAlert = UnknownCA
# ===========================================================
[6-client-auth-TLSv1.3-request-post-handshake]
ssl_conf = 6-client-auth-TLSv1.3-request-post-handshake-ssl
[6-client-auth-TLSv1.3-request-post-handshake-ssl]
server = 6-client-auth-TLSv1.3-request-post-handshake-server
client = 6-client-auth-TLSv1.3-request-post-handshake-client
[6-client-auth-TLSv1.3-request-post-handshake-server]
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
VerifyMode = RequestPostHandshake
[6-client-auth-TLSv1.3-request-post-handshake-client]
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
VerifyMode = Peer
[test-6]
ExpectedResult = ServerFail
HandshakeMode = PostHandshakeAuth
# ===========================================================
[7-client-auth-TLSv1.3-require-fail-post-handshake]
ssl_conf = 7-client-auth-TLSv1.3-require-fail-post-handshake-ssl
[7-client-auth-TLSv1.3-require-fail-post-handshake-ssl]
server = 7-client-auth-TLSv1.3-require-fail-post-handshake-server
client = 7-client-auth-TLSv1.3-require-fail-post-handshake-client
[7-client-auth-TLSv1.3-require-fail-post-handshake-server]
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/root-cert.pem
VerifyMode = RequirePostHandshake
[7-client-auth-TLSv1.3-require-fail-post-handshake-client]
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
VerifyMode = Peer
[test-7]
ExpectedResult = ServerFail
HandshakeMode = PostHandshakeAuth
# ===========================================================
[8-client-auth-TLSv1.3-require-post-handshake]
ssl_conf = 8-client-auth-TLSv1.3-require-post-handshake-ssl
[8-client-auth-TLSv1.3-require-post-handshake-ssl]
server = 8-client-auth-TLSv1.3-require-post-handshake-server
client = 8-client-auth-TLSv1.3-require-post-handshake-client
[8-client-auth-TLSv1.3-require-post-handshake-server]
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
CipherString = DEFAULT
ClientSignatureAlgorithms = PSS+SHA256
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/root-cert.pem
VerifyMode = RequestPostHandshake
[8-client-auth-TLSv1.3-require-post-handshake-client]
Certificate = ${ENV::TEST_CERTS_DIR}/ee-client-chain.pem
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
PrivateKey = ${ENV::TEST_CERTS_DIR}/ee-key.pem
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
VerifyMode = Peer
[test-8]
ExpectedClientCANames = empty
ExpectedClientCertType = RSA
ExpectedClientSignHash = SHA256
ExpectedClientSignType = RSA-PSS
ExpectedResult = Success
HandshakeMode = PostHandshakeAuth
# ===========================================================
[9-client-auth-TLSv1.3-require-non-empty-names-post-handshake]
ssl_conf = 9-client-auth-TLSv1.3-require-non-empty-names-post-handshake-ssl
[9-client-auth-TLSv1.3-require-non-empty-names-post-handshake-ssl]
server = 9-client-auth-TLSv1.3-require-non-empty-names-post-handshake-server
client = 9-client-auth-TLSv1.3-require-non-empty-names-post-handshake-client
[9-client-auth-TLSv1.3-require-non-empty-names-post-handshake-server]
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
CipherString = DEFAULT
ClientCAFile = ${ENV::TEST_CERTS_DIR}/root-cert.pem
ClientSignatureAlgorithms = PSS+SHA256
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/root-cert.pem
VerifyMode = RequestPostHandshake
[9-client-auth-TLSv1.3-require-non-empty-names-post-handshake-client]
Certificate = ${ENV::TEST_CERTS_DIR}/ee-client-chain.pem
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
PrivateKey = ${ENV::TEST_CERTS_DIR}/ee-key.pem
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
VerifyMode = Peer
[test-9]
ExpectedClientCANames = ${ENV::TEST_CERTS_DIR}/root-cert.pem
ExpectedClientCertType = RSA
ExpectedClientSignHash = SHA256
ExpectedClientSignType = RSA-PSS
ExpectedResult = Success
HandshakeMode = PostHandshakeAuth
# ===========================================================
[10-client-auth-TLSv1.3-noroot-post-handshake]
ssl_conf = 10-client-auth-TLSv1.3-noroot-post-handshake-ssl
[10-client-auth-TLSv1.3-noroot-post-handshake-ssl]
server = 10-client-auth-TLSv1.3-noroot-post-handshake-server
client = 10-client-auth-TLSv1.3-noroot-post-handshake-client
[10-client-auth-TLSv1.3-noroot-post-handshake-server]
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
VerifyMode = RequirePostHandshake
[10-client-auth-TLSv1.3-noroot-post-handshake-client]
Certificate = ${ENV::TEST_CERTS_DIR}/ee-client-chain.pem
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
PrivateKey = ${ENV::TEST_CERTS_DIR}/ee-key.pem
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
VerifyMode = Peer
[test-10]
ExpectedResult = ServerFail
ExpectedServerAlert = UnknownCA
HandshakeMode = PostHandshakeAuth
# ===========================================================
[11-client-auth-TLSv1.3-request-force-client-post-handshake]
ssl_conf = 11-client-auth-TLSv1.3-request-force-client-post-handshake-ssl
[11-client-auth-TLSv1.3-request-force-client-post-handshake-ssl]
server = 11-client-auth-TLSv1.3-request-force-client-post-handshake-server
client = 11-client-auth-TLSv1.3-request-force-client-post-handshake-client
[11-client-auth-TLSv1.3-request-force-client-post-handshake-server]
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
VerifyMode = RequestPostHandshake
[11-client-auth-TLSv1.3-request-force-client-post-handshake-client]
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
VerifyMode = Peer
[test-11]
ExpectedResult = Success
HandshakeMode = PostHandshakeAuth
client = 11-client-auth-TLSv1.3-request-force-client-post-handshake-client-extra
[11-client-auth-TLSv1.3-request-force-client-post-handshake-client-extra]
ForcePHA = Yes
# ===========================================================
[12-client-auth-TLSv1.3-request-force-server-post-handshake]
ssl_conf = 12-client-auth-TLSv1.3-request-force-server-post-handshake-ssl
[12-client-auth-TLSv1.3-request-force-server-post-handshake-ssl]
server = 12-client-auth-TLSv1.3-request-force-server-post-handshake-server
client = 12-client-auth-TLSv1.3-request-force-server-post-handshake-client
[12-client-auth-TLSv1.3-request-force-server-post-handshake-server]
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
VerifyMode = RequestPostHandshake
[12-client-auth-TLSv1.3-request-force-server-post-handshake-client]
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
VerifyMode = Peer
[test-12]
ExpectedResult = ClientFail
HandshakeMode = PostHandshakeAuth
server = 12-client-auth-TLSv1.3-request-force-server-post-handshake-server-extra
[12-client-auth-TLSv1.3-request-force-server-post-handshake-server-extra]
ForcePHA = Yes
# ===========================================================
[13-client-auth-TLSv1.3-request-force-both-post-handshake]
ssl_conf = 13-client-auth-TLSv1.3-request-force-both-post-handshake-ssl
[13-client-auth-TLSv1.3-request-force-both-post-handshake-ssl]
server = 13-client-auth-TLSv1.3-request-force-both-post-handshake-server
client = 13-client-auth-TLSv1.3-request-force-both-post-handshake-client
[13-client-auth-TLSv1.3-request-force-both-post-handshake-server]
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
VerifyMode = RequestPostHandshake
[13-client-auth-TLSv1.3-request-force-both-post-handshake-client]
CipherString = DEFAULT
MaxProtocol = TLSv1.3
MinProtocol = TLSv1.3
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
VerifyMode = Peer
[test-13]
ExpectedResult = Success
HandshakeMode = PostHandshakeAuth
server = 13-client-auth-TLSv1.3-request-force-both-post-handshake-server-extra
client = 13-client-auth-TLSv1.3-request-force-both-post-handshake-client-extra
[13-client-auth-TLSv1.3-request-force-both-post-handshake-server-extra]
ForcePHA = Yes
[13-client-auth-TLSv1.3-request-force-both-post-handshake-client-extra]
ForcePHA = Yes

View file

@ -0,0 +1,293 @@
# -*- mode: perl; -*-
# Copyright 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
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
## Test TLSv1.3 certificate authentication
## Similar to 04-client_auth.conf.in output, but specific for
## TLSv1.3 and post-handshake authentication
use strict;
use warnings;
package ssltests;
use OpenSSL::Test::Utils;
our @tests = (
{
name => "server-auth-TLSv1.3",
server => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
},
client => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
},
test => {
"ExpectedResult" => "Success",
},
},
{
name => "client-auth-TLSv1.3-request",
server => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
"VerifyMode" => "Request",
},
client => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
},
test => {
"ExpectedResult" => "Success",
},
},
{
name => "client-auth-TLSv1.3-require-fail",
server => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
"VerifyCAFile" => test_pem("root-cert.pem"),
"VerifyMode" => "Require",
},
client => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
},
test => {
"ExpectedResult" => "ServerFail",
"ExpectedServerAlert" => "HandshakeFailure",
},
},
{
name => "client-auth-TLSv1.3-require",
server => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
"ClientSignatureAlgorithms" => "PSS+SHA256",
"VerifyCAFile" => test_pem("root-cert.pem"),
"VerifyMode" => "Request",
},
client => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
"Certificate" => test_pem("ee-client-chain.pem"),
"PrivateKey" => test_pem("ee-key.pem"),
},
test => {
"ExpectedResult" => "Success",
"ExpectedClientCertType" => "RSA",
"ExpectedClientSignType" => "RSA-PSS",
"ExpectedClientSignHash" => "SHA256",
"ExpectedClientCANames" => "empty"
},
},
{
name => "client-auth-TLSv1.3-require-non-empty-names",
server => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
"ClientSignatureAlgorithms" => "PSS+SHA256",
"ClientCAFile" => test_pem("root-cert.pem"),
"VerifyCAFile" => test_pem("root-cert.pem"),
"VerifyMode" => "Request",
},
client => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
"Certificate" => test_pem("ee-client-chain.pem"),
"PrivateKey" => test_pem("ee-key.pem"),
},
test => {
"ExpectedResult" => "Success",
"ExpectedClientCertType" => "RSA",
"ExpectedClientSignType" => "RSA-PSS",
"ExpectedClientSignHash" => "SHA256",
"ExpectedClientCANames" => test_pem("root-cert.pem"),
},
},
{
name => "client-auth-TLSv1.3-noroot",
server => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
"VerifyMode" => "Require",
},
client => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
"Certificate" => test_pem("ee-client-chain.pem"),
"PrivateKey" => test_pem("ee-key.pem"),
},
test => {
"ExpectedResult" => "ServerFail",
"ExpectedServerAlert" => "UnknownCA",
},
},
{
name => "client-auth-TLSv1.3-request-post-handshake",
server => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
"VerifyMode" => "RequestPostHandshake",
},
client => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
},
test => {
"ExpectedResult" => "ServerFail",
"HandshakeMode" => "PostHandshakeAuth",
},
},
{
name => "client-auth-TLSv1.3-require-fail-post-handshake",
server => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
"VerifyCAFile" => test_pem("root-cert.pem"),
"VerifyMode" => "RequirePostHandshake",
},
client => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
},
test => {
"ExpectedResult" => "ServerFail",
"HandshakeMode" => "PostHandshakeAuth",
},
},
{
name => "client-auth-TLSv1.3-require-post-handshake",
server => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
"ClientSignatureAlgorithms" => "PSS+SHA256",
"VerifyCAFile" => test_pem("root-cert.pem"),
"VerifyMode" => "RequestPostHandshake",
},
client => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
"Certificate" => test_pem("ee-client-chain.pem"),
"PrivateKey" => test_pem("ee-key.pem"),
},
test => {
"ExpectedResult" => "Success",
"HandshakeMode" => "PostHandshakeAuth",
"ExpectedClientCertType" => "RSA",
"ExpectedClientSignType" => "RSA-PSS",
"ExpectedClientSignHash" => "SHA256",
"ExpectedClientCANames" => "empty"
},
},
{
name => "client-auth-TLSv1.3-require-non-empty-names-post-handshake",
server => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
"ClientSignatureAlgorithms" => "PSS+SHA256",
"ClientCAFile" => test_pem("root-cert.pem"),
"VerifyCAFile" => test_pem("root-cert.pem"),
"VerifyMode" => "RequestPostHandshake",
},
client => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
"Certificate" => test_pem("ee-client-chain.pem"),
"PrivateKey" => test_pem("ee-key.pem"),
},
test => {
"ExpectedResult" => "Success",
"HandshakeMode" => "PostHandshakeAuth",
"ExpectedClientCertType" => "RSA",
"ExpectedClientSignType" => "RSA-PSS",
"ExpectedClientSignHash" => "SHA256",
"ExpectedClientCANames" => test_pem("root-cert.pem"),
},
},
{
name => "client-auth-TLSv1.3-noroot-post-handshake",
server => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
"VerifyMode" => "RequirePostHandshake",
},
client => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
"Certificate" => test_pem("ee-client-chain.pem"),
"PrivateKey" => test_pem("ee-key.pem"),
},
test => {
"ExpectedResult" => "ServerFail",
"HandshakeMode" => "PostHandshakeAuth",
"ExpectedServerAlert" => "UnknownCA",
},
},
{
name => "client-auth-TLSv1.3-request-force-client-post-handshake",
server => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
"VerifyMode" => "RequestPostHandshake",
},
client => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
extra => {
"ForcePHA" => "Yes",
},
},
test => {
"ExpectedResult" => "Success",
"HandshakeMode" => "PostHandshakeAuth",
},
},
{
name => "client-auth-TLSv1.3-request-force-server-post-handshake",
server => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
"VerifyMode" => "RequestPostHandshake",
extra => {
"ForcePHA" => "Yes",
},
},
client => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
},
test => {
"ExpectedResult" => "ClientFail",
"HandshakeMode" => "PostHandshakeAuth",
},
},
{
name => "client-auth-TLSv1.3-request-force-both-post-handshake",
server => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
"VerifyMode" => "RequestPostHandshake",
extra => {
"ForcePHA" => "Yes",
},
},
client => {
"MinProtocol" => "TLSv1.3",
"MaxProtocol" => "TLSv1.3",
extra => {
"ForcePHA" => "Yes",
},
},
test => {
"ExpectedResult" => "Success",
"HandshakeMode" => "PostHandshakeAuth",
},
},
);

View file

@ -369,6 +369,7 @@ static const test_enum ssl_handshake_modes[] = {
{"RenegotiateClient", SSL_TEST_HANDSHAKE_RENEG_CLIENT},
{"KeyUpdateServer", SSL_TEST_HANDSHAKE_KEY_UPDATE_SERVER},
{"KeyUpdateClient", SSL_TEST_HANDSHAKE_KEY_UPDATE_CLIENT},
{"PostHandshakeAuth", SSL_TEST_HANDSHAKE_POST_HANDSHAKE_AUTH},
};
__owur static int parse_handshake_mode(SSL_TEST_CTX *test_ctx, const char *value)
@ -622,6 +623,11 @@ __owur static int parse_expected_client_ca_names(SSL_TEST_CTX *test_ctx,
IMPLEMENT_SSL_TEST_STRING_OPTION(SSL_TEST_CTX, test, expected_cipher)
/* Client and Server ForcePHA */
IMPLEMENT_SSL_TEST_BOOL_OPTION(SSL_TEST_CLIENT_CONF, client, force_pha)
IMPLEMENT_SSL_TEST_BOOL_OPTION(SSL_TEST_SERVER_CONF, server, force_pha)
/* Known test options and their corresponding parse methods. */
/* Top-level options. */
@ -676,6 +682,7 @@ static const ssl_test_client_option ssl_test_client_options[] = {
{ "SRPUser", &parse_client_srp_user },
{ "SRPPassword", &parse_client_srp_password },
{ "MaxFragmentLenExt", &parse_max_fragment_len_mode },
{ "ForcePHA", &parse_client_force_pha },
};
/* Nested server options. */
@ -692,6 +699,7 @@ static const ssl_test_server_option ssl_test_server_options[] = {
{ "CertStatus", &parse_certstatus },
{ "SRPUser", &parse_server_srp_user },
{ "SRPPassword", &parse_server_srp_password },
{ "ForcePHA", &parse_server_force_pha },
};
SSL_TEST_CTX *SSL_TEST_CTX_new()

View file

@ -73,7 +73,8 @@ typedef enum {
SSL_TEST_HANDSHAKE_RENEG_SERVER,
SSL_TEST_HANDSHAKE_RENEG_CLIENT,
SSL_TEST_HANDSHAKE_KEY_UPDATE_SERVER,
SSL_TEST_HANDSHAKE_KEY_UPDATE_CLIENT
SSL_TEST_HANDSHAKE_KEY_UPDATE_CLIENT,
SSL_TEST_HANDSHAKE_POST_HANDSHAKE_AUTH
} ssl_handshake_mode_t;
typedef enum {
@ -107,6 +108,8 @@ typedef struct {
char *reneg_ciphers;
char *srp_user;
char *srp_password;
/* Forced PHA */
int force_pha;
} SSL_TEST_CLIENT_CONF;
typedef struct {
@ -122,6 +125,8 @@ typedef struct {
/* An SRP user known to the server. */
char *srp_user;
char *srp_password;
/* Forced PHA */
int force_pha;
} SSL_TEST_SERVER_CONF;
typedef struct {

View file

@ -3306,6 +3306,65 @@ end:
return testresult;
}
#ifndef OPENSSL_NO_TLS1_3
static int test_pha_key_update(void)
{
SSL_CTX *cctx = NULL, *sctx = NULL;
SSL *clientssl = NULL, *serverssl = NULL;
int testresult = 0;
if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(),
TLS_client_method(),
&sctx, &cctx, cert, privkey)))
return 0;
if (!TEST_true(SSL_CTX_set_min_proto_version(sctx, TLS1_3_VERSION))
|| !TEST_true(SSL_CTX_set_max_proto_version(sctx, TLS1_3_VERSION))
|| !TEST_true(SSL_CTX_set_min_proto_version(cctx, TLS1_3_VERSION))
|| !TEST_true(SSL_CTX_set_max_proto_version(cctx, TLS1_3_VERSION)))
goto end;
if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
NULL, NULL)))
goto end;
SSL_force_post_handshake_auth(clientssl);
if (!TEST_true(create_ssl_connection(serverssl, clientssl,
SSL_ERROR_NONE)))
goto end;
SSL_set_verify(serverssl, SSL_VERIFY_PEER, NULL);
if (!TEST_true(SSL_verify_client_post_handshake(serverssl)))
goto end;
if (!TEST_true(SSL_key_update(clientssl, SSL_KEY_UPDATE_NOT_REQUESTED)))
goto end;
/* Start handshake on the server */
if (!TEST_int_eq(SSL_do_handshake(serverssl), 1))
goto end;
/* Starts with SSL_connect(), but it's really just SSL_do_handshake() */
if (!TEST_true(create_ssl_connection(serverssl, clientssl,
SSL_ERROR_NONE)))
goto end;
SSL_shutdown(clientssl);
SSL_shutdown(serverssl);
testresult = 1;
end:
SSL_free(serverssl);
SSL_free(clientssl);
SSL_CTX_free(sctx);
SSL_CTX_free(cctx);
return testresult;
}
#endif
int setup_tests(void)
{
if (!TEST_ptr(cert = test_get_argument(0))
@ -3352,6 +3411,7 @@ int setup_tests(void)
ADD_TEST(test_tls13_psk);
ADD_ALL_TESTS(test_custom_exts, 5);
ADD_TEST(test_stateless);
ADD_TEST(test_pha_key_update);
#else
ADD_ALL_TESTS(test_custom_exts, 3);
#endif

View file

@ -474,3 +474,5 @@ SSL_CTX_set_tlsext_max_fragment_length 474 1_1_1 EXIST::FUNCTION:
SSL_set_tlsext_max_fragment_length 475 1_1_1 EXIST::FUNCTION:
SSL_SESSION_get_max_fragment_length 476 1_1_1 EXIST::FUNCTION:
SSL_stateless 477 1_1_1 EXIST::FUNCTION:
SSL_verify_client_post_handshake 478 1_1_1 EXIST::FUNCTION:
SSL_force_post_handshake_auth 479 1_1_1 EXIST::FUNCTION:

View file

@ -79,6 +79,7 @@ use constant {
EXT_SUPPORTED_VERSIONS => 43,
EXT_COOKIE => 44,
EXT_PSK_KEX_MODES => 45,
EXT_POST_HANDSHAKE_AUTH => 49,
EXT_SIG_ALGS_CERT => 50,
EXT_RENEGOTIATE => 65281,
EXT_NPN => 13172,

View file

@ -53,7 +53,8 @@ use constant {
KEY_SHARE_SRV_EXTENSION => 0x00020000,
PSK_KEX_MODES_EXTENSION => 0x00040000,
KEY_SHARE_HRR_EXTENSION => 0x00080000,
SUPPORTED_GROUPS_SRV_EXTENSION => 0x00100000
SUPPORTED_GROUPS_SRV_EXTENSION => 0x00100000,
POST_HANDSHAKE_AUTH_CLI_EXTENSION => 0x00200000
};
our @handmessages = ();