{"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}
};
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;
#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}
};
int isdtls = 0;
#endif
char *psksessf = NULL;
+ int force_pha = 0;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
case OPT_EARLY_DATA:
early_data_file = opt_arg();
break;
+ case OPT_FORCE_PHA:
+ force_pha = 1;
+ break;
}
}
if (count4or6 >= 2) {
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");
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));
-# 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
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:*
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:*
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
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
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
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
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
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
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
[B<-ctlogfile>]
[B<-keylogfile file>]
[B<-early_data file>]
+[B<-force_pha>]
[B<target>]
=head1 DESCRIPTION
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
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
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
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
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
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
=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
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
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
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.
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
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);
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
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;
{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"},
{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),
"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),
"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"},
"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),
{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),
"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),
"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),
"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),
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);
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;
+}
#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 */
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,
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;
__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,
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 */
/* 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,
return 1;
}
+
+static int init_post_handshake_auth(SSL *s, unsigned int context)
+{
+ s->post_handshake_auth = SSL_PHA_NONE;
+
+ return 1;
+}
#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
*/
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;
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
*/
/*
- * 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.
*
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;
}
* 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,
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;
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);
if (s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT &&
!tls1_check_chain(s, NULL, NULL, NULL, -2))
return 0;
+
return 1;
}
}
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;
}
}
+ if (s->post_handshake_auth == SSL_PHA_REQUESTED)
+ return WORK_FINISHED_STOP;
return WORK_FINISHED_CONTINUE;
}
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
/*
- * 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
/*
* 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,
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;
/*
/* 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
*/
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;
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;
/*
* 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)
*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;
+}
/*
- * 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
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,
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,
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);
/*
- * 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.
*
*/
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;
* 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
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;
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:
* 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;
}
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;
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,
}
done:
+ s->certreqs_sent++;
s->s3->tmp.cert_request = 1;
return 1;
}
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,
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);
}
}
+ /*
+ * 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;
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
{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[] = {
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
#include <openssl/srp.h>
#endif
+#include "../ssl/ssl_locl.h"
#include "internal/sockets.h"
#include "internal/nelem.h"
#include "handshake_helper.h"
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. */
|| 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;
}
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;
}
/*
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:
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],
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],
$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)
# 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.
&& 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) {
--- /dev/null
+# 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
+
+
--- /dev/null
+# -*- 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",
+ },
+ },
+);
{"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)
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. */
{ "SRPUser", &parse_client_srp_user },
{ "SRPPassword", &parse_client_srp_password },
{ "MaxFragmentLenExt", &parse_max_fragment_len_mode },
+ { "ForcePHA", &parse_client_force_pha },
};
/* Nested 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()
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 {
char *reneg_ciphers;
char *srp_user;
char *srp_password;
+ /* Forced PHA */
+ int force_pha;
} SSL_TEST_CLIENT_CONF;
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 {
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))
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
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:
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,
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 = ();