Commit 9d75dce3 authored by Todd Short's avatar Todd Short Committed by Matt Caswell
Browse files

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: default avatarBen Kaduk <kaduk@mit.edu>
Reviewed-by: default avatarMatt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/4964)
parent 633a8829
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -666,6 +666,7 @@ static STRINT_PAIR tlsext_types[] = {
    {"psk", TLSEXT_TYPE_psk},
    {"psk", TLSEXT_TYPE_psk},
    {"psk kex modes", TLSEXT_TYPE_psk_kex_modes},
    {"psk kex modes", TLSEXT_TYPE_psk_kex_modes},
    {"certificate authorities", TLSEXT_TYPE_certificate_authorities},
    {"certificate authorities", TLSEXT_TYPE_certificate_authorities},
    {"post handshake auth", TLSEXT_TYPE_post_handshake_auth},
    {NULL}
    {NULL}
};
};


+9 −0
Original line number Original line Diff line number Diff line
@@ -602,6 +602,7 @@ typedef enum OPTION_choice {
    OPT_CT, OPT_NOCT, OPT_CTLOG_FILE,
    OPT_CT, OPT_NOCT, OPT_CTLOG_FILE,
#endif
#endif
    OPT_DANE_TLSA_RRDATA, OPT_DANE_EE_NO_NAME,
    OPT_DANE_TLSA_RRDATA, OPT_DANE_EE_NO_NAME,
    OPT_FORCE_PHA,
    OPT_R_ENUM
    OPT_R_ENUM
} OPTION_CHOICE;
} OPTION_CHOICE;


@@ -788,6 +789,7 @@ const OPTIONS s_client_options[] = {
#endif
#endif
    {"keylogfile", OPT_KEYLOG_FILE, '>', "Write TLS secrets to file"},
    {"keylogfile", OPT_KEYLOG_FILE, '>', "Write TLS secrets to file"},
    {"early_data", OPT_EARLY_DATA, '<', "File to send as early data"},
    {"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}
    {NULL, OPT_EOF, 0x00, NULL}
};
};


@@ -958,6 +960,7 @@ int s_client_main(int argc, char **argv)
    int isdtls = 0;
    int isdtls = 0;
#endif
#endif
    char *psksessf = NULL;
    char *psksessf = NULL;
    int force_pha = 0;


    FD_ZERO(&readfds);
    FD_ZERO(&readfds);
    FD_ZERO(&writefds);
    FD_ZERO(&writefds);
@@ -1469,6 +1472,9 @@ int s_client_main(int argc, char **argv)
        case OPT_EARLY_DATA:
        case OPT_EARLY_DATA:
            early_data_file = opt_arg();
            early_data_file = opt_arg();
            break;
            break;
        case OPT_FORCE_PHA:
            force_pha = 1;
            break;
        }
        }
    }
    }
    if (count4or6 >= 2) {
    if (count4or6 >= 2) {
@@ -1904,6 +1910,9 @@ int s_client_main(int argc, char **argv)
    if (con == NULL)
    if (con == NULL)
        goto end;
        goto end;


    if (force_pha)
        SSL_force_post_handshake_auth(con);

    if (sess_in != NULL) {
    if (sess_in != NULL) {
        SSL_SESSION *sess;
        SSL_SESSION *sess;
        BIO *stmp = BIO_new_file(sess_in, "r");
        BIO *stmp = BIO_new_file(sess_in, "r");
+13 −0
Original line number Original line Diff line number Diff line
@@ -2501,6 +2501,19 @@ static int sv_body(int s, int stype, int prot, unsigned char *context)
                    i = 0;
                    i = 0;
                    continue;
                    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') {
                if (buf[0] == 'P') {
                    static const char *str = "Lets print some clear text\n";
                    static const char *str = "Lets print some clear text\n";
                    BIO_write(SSL_get_wbio(con), str, strlen(str));
                    BIO_write(SSL_get_wbio(con), str, strlen(str));
+16 −1
Original line number Original line Diff line number Diff line
# 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
# Licensed under the OpenSSL license (the "License").  You may not use
# this file except in compliance with the License.  You can obtain a copy
# 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_USE_RSAPRIVATEKEY_FILE:206:SSL_use_RSAPrivateKey_file
SSL_F_SSL_VALIDATE_CT:400:ssl_validate_ct
SSL_F_SSL_VALIDATE_CT:400:ssl_validate_ct
SSL_F_SSL_VERIFY_CERT_CHAIN:207:ssl_verify_cert_chain
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:208:SSL_write
SSL_F_SSL_WRITE_EARLY_DATA:526:SSL_write_early_data
SSL_F_SSL_WRITE_EARLY_DATA:526:SSL_write_early_data
SSL_F_SSL_WRITE_EARLY_FINISH:527:*
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_FINAL_FINISH_MAC:605:tls13_final_finish_mac
SSL_F_TLS13_GENERATE_SECRET:591:tls13_generate_secret
SSL_F_TLS13_GENERATE_SECRET:591:tls13_generate_secret
SSL_F_TLS13_HKDF_EXPAND:561:tls13_hkdf_expand
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_TLS13_SETUP_KEY_BLOCK:441:tls13_setup_key_block
SSL_F_TLS1_CHANGE_CIPHER_STATE:209:tls1_change_cipher_state
SSL_F_TLS1_CHANGE_CIPHER_STATE:209:tls1_change_cipher_state
SSL_F_TLS1_CHECK_DUPLICATE_EXTENSIONS:341:*
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_MAXFRAGMENTLEN:549:tls_construct_ctos_maxfragmentlen
SSL_F_TLS_CONSTRUCT_CTOS_NPN:471:tls_construct_ctos_npn
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_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: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_PSK_KEX_MODES:509:tls_construct_ctos_psk_kex_modes
SSL_F_TLS_CONSTRUCT_CTOS_RENEGOTIATE:473:tls_construct_ctos_renegotiate
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_EMS:570:tls_parse_ctos_ems
SSL_F_TLS_PARSE_CTOS_KEY_SHARE:463:tls_parse_ctos_key_share
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_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: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_PSK_KEX_MODES:572:tls_parse_ctos_psk_kex_modes
SSL_F_TLS_PARSE_CTOS_RENEGOTIATE:464:tls_parse_ctos_renegotiate
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_ERROR_SETTING_TLSA_BASE_DOMAIN:204:error setting tlsa base domain
SSL_R_EXCEEDS_MAX_FRAGMENT_SIZE:194:exceeds max fragment size
SSL_R_EXCEEDS_MAX_FRAGMENT_SIZE:194:exceeds max fragment size
SSL_R_EXCESSIVE_MESSAGE_SIZE:152:excessive message 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_EXTRA_DATA_IN_MESSAGE:153:extra data in message
SSL_R_EXT_LENGTH_MISMATCH:163:ext length mismatch
SSL_R_EXT_LENGTH_MISMATCH:163:ext length mismatch
SSL_R_FAILED_TO_INIT_ASYNC:405:failed to init async
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_CERTIFICATE_OR_ALG:238:invalid certificate or alg
SSL_R_INVALID_COMMAND:280:invalid command
SSL_R_INVALID_COMMAND:280:invalid command
SSL_R_INVALID_COMPRESSION_ALGORITHM:341:invalid compression algorithm
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_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_CT_VALIDATION_TYPE:212:invalid ct validation type
SSL_R_INVALID_KEY_UPDATE_TYPE:120:invalid key update 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_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_DH_KEY:171:missing tmp dh key
SSL_R_MISSING_TMP_ECDH_KEY:311:missing tmp ecdh 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_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_APPLICATION_PROTOCOL:235:no application protocol
SSL_R_NO_CERTIFICATES_RETURNED:176:no certificates returned
SSL_R_NO_CERTIFICATES_RETURNED:176:no certificates returned
SSL_R_NO_CERTIFICATE_ASSIGNED:177:no certificate assigned
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_BAD_PREFIX:391:pem name bad prefix
SSL_R_PEM_NAME_TOO_SHORT:392:pem name too short
SSL_R_PEM_NAME_TOO_SHORT:392:pem name too short
SSL_R_PIPELINE_FAILURE:406:pipeline failure
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_PROTOCOL_IS_SHUTDOWN:207:protocol is shutdown
SSL_R_PSK_IDENTITY_NOT_FOUND:223:psk identity not found
SSL_R_PSK_IDENTITY_NOT_FOUND:223:psk identity not found
SSL_R_PSK_NO_CLIENT_CB:224:psk no client cb
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_RENEGOTIATE_EXT_TOO_LONG:335:renegotiate ext too long
SSL_R_RENEGOTIATION_ENCODING_ERR:336:renegotiation encoding err
SSL_R_RENEGOTIATION_ENCODING_ERR:336:renegotiation encoding err
SSL_R_RENEGOTIATION_MISMATCH:337:renegotiation mismatch
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_CIPHER_MISSING:215:required cipher missing
SSL_R_REQUIRED_COMPRESSION_ALGORITHM_MISSING:342:\
SSL_R_REQUIRED_COMPRESSION_ALGORITHM_MISSING:342:\
	required compression algorithm missing
	required compression algorithm missing
+6 −0
Original line number Original line Diff line number Diff line
@@ -118,6 +118,7 @@ B<openssl> B<s_client>
[B<-ctlogfile>]
[B<-ctlogfile>]
[B<-keylogfile file>]
[B<-keylogfile file>]
[B<-early_data file>]
[B<-early_data file>]
[B<-force_pha>]
[B<target>]
[B<target>]


=head1 DESCRIPTION
=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
to the server. This will only work with resumed sessions that support early
data and when the server accepts the early data.
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]>
=item B<[target]>


Rather than providing B<-connect>, the target hostname and optional port may
Rather than providing B<-connect>, the target hostname and optional port may
Loading