Change Post Handshake auth so that it is opt-in

Having post handshake auth automatically switched on breaks some
applications written for TLSv1.2. This changes things so that an explicit
function call is required for a client to indicate support for
post-handshake auth.

Fixes #6933.

Reviewed-by: Tim Hudson <tjh@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/6938)
diff --git a/apps/s_client.c b/apps/s_client.c
index 8f9ad9d..dcaa10c 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -595,7 +595,7 @@
     OPT_CT, OPT_NOCT, OPT_CTLOG_FILE,
 #endif
     OPT_DANE_TLSA_RRDATA, OPT_DANE_EE_NO_NAME,
-    OPT_FORCE_PHA,
+    OPT_ENABLE_PHA,
     OPT_R_ENUM
 } OPTION_CHOICE;
 
@@ -786,7 +786,7 @@
 #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"},
+    {"enable_pha", OPT_ENABLE_PHA, '-', "Enable post-handshake-authentication"},
     {NULL, OPT_EOF, 0x00, NULL}
 };
 
@@ -975,7 +975,7 @@
     int isdtls = 0;
 #endif
     char *psksessf = NULL;
-    int force_pha = 0;
+    int enable_pha = 0;
 
     FD_ZERO(&readfds);
     FD_ZERO(&writefds);
@@ -1492,8 +1492,8 @@
         case OPT_EARLY_DATA:
             early_data_file = opt_arg();
             break;
-        case OPT_FORCE_PHA:
-            force_pha = 1;
+        case OPT_ENABLE_PHA:
+            enable_pha = 1;
             break;
         }
     }
@@ -1944,8 +1944,8 @@
     if (con == NULL)
         goto end;
 
-    if (force_pha)
-        SSL_force_post_handshake_auth(con);
+    if (enable_pha)
+        SSL_set_post_handshake_auth(con, 1);
 
     if (sess_in != NULL) {
         SSL_SESSION *sess;
diff --git a/doc/man1/s_client.pod b/doc/man1/s_client.pod
index 80152e1..fa5cb0a 100644
--- a/doc/man1/s_client.pod
+++ b/doc/man1/s_client.pod
@@ -134,7 +134,7 @@
 [B<-ctlogfile>]
 [B<-keylogfile file>]
 [B<-early_data file>]
-[B<-force_pha>]
+[B<-enable_pha>]
 [B<target>]
 
 =head1 DESCRIPTION
@@ -700,10 +700,10 @@
 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>
+=item B<-enable_pha>
 
-For TLSv1.3 only, always send the Post-Handshake Authentication extension,
-whether or not a certificate has been provided via B<-cert>.
+For TLSv1.3 only, send the Post-Handshake Authentication extension. This will
+happen whether or not a certificate has been provided via B<-cert>.
 
 =item B<[target]>
 
diff --git a/doc/man3/SSL_CTX_set_verify.pod b/doc/man3/SSL_CTX_set_verify.pod
index 7165547..173f006 100644
--- a/doc/man3/SSL_CTX_set_verify.pod
+++ b/doc/man3/SSL_CTX_set_verify.pod
@@ -7,7 +7,7 @@
 SSL_CTX_set_verify_depth, SSL_set_verify_depth,
 SSL_verify_cb,
 SSL_verify_client_post_handshake,
-SSL_force_post_handshake_auth
+SSL_set_post_handshake_auth
 - set peer certificate verification parameters
 
 =head1 SYNOPSIS
@@ -24,7 +24,7 @@
  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);
+ void SSL_set_post_handshake_auth(SSL *ssl, int val);
 
 =head1 DESCRIPTION
 
@@ -48,11 +48,12 @@
 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_set_post_handshake_auth() enables the Post-Handshake Authentication
+extension to be added to the ClientHello such that post-handshake authentication
+can be requested by the server. If B<val> is 0 then the extension is not sent,
+otherwise it is. By default the extension is not sent. 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 CertificateRequest message to be
 sent by a server on the given B<ssl> connection. The SSL_VERIFY_PEER flag must
@@ -341,7 +342,7 @@
 =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.
+and SSL_set_post_handshake_auth() functions were added in OpenSSL 1.1.1.
 
 =head1 COPYRIGHT
 
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 155d651..b61119c 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -1898,7 +1898,7 @@
 __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);
+void SSL_set_post_handshake_auth(SSL *s, int val);
 
 __owur const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx);
 __owur const SSL_METHOD *SSL_get_ssl_method(SSL *s);
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index a486356..89570fb 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -5455,9 +5455,9 @@
     return -1;
 }
 
-void SSL_force_post_handshake_auth(SSL *ssl)
+void SSL_set_post_handshake_auth(SSL *ssl, int val)
 {
-    ssl->pha_forced = 1;
+    ssl->pha_enabled = val;
 }
 
 int SSL_verify_client_post_handshake(SSL *ssl)
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 6d6404b..0d98110 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1391,7 +1391,7 @@
     int key_update;
     /* Post-handshake authentication state */
     SSL_PHA_STATE post_handshake_auth;
-    int pha_forced;
+    int pha_enabled;
     uint8_t* pha_context;
     size_t pha_context_len;
     int certreqs_sent;
diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
index 86d6189..2d5b60a 100644
--- a/ssl/statem/extensions_clnt.c
+++ b/ssl/statem/extensions_clnt.c
@@ -1193,23 +1193,8 @@
                                                   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;
-    }
+    if (!s->pha_enabled)
+        return EXT_RETURN_NOT_SENT;
 
     /* construct extension - 0 length, no contents */
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_post_handshake_auth)
diff --git a/test/handshake_helper.c b/test/handshake_helper.c
index c40a0e7..a5b8d80 100644
--- a/test/handshake_helper.c
+++ b/test/handshake_helper.c
@@ -726,8 +726,8 @@
     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);
+    if (extra->client.enable_pha)
+        SSL_set_post_handshake_auth(client, 1);
 }
 
 /* The status for each connection phase. */
diff --git a/test/recipes/70-test_tls13messages.t b/test/recipes/70-test_tls13messages.t
index 35f36b6..be6a2db 100644
--- a/test/recipes/70-test_tls13messages.t
+++ b/test/recipes/70-test_tls13messages.t
@@ -214,7 +214,7 @@
 
 #Test 6: A client auth handshake
 $proxy->clear();
-$proxy->clientflags("-cert ".srctop_file("apps", "server.pem"));
+$proxy->clientflags("-enable_pha -cert ".srctop_file("apps", "server.pem"));
 $proxy->serverflags("-Verify 5");
 $proxy->start();
 checkhandshake($proxy, checkhandshake::CLIENT_AUTH_HANDSHAKE,
diff --git a/test/ssl-tests/26-tls13_client_auth.conf b/test/ssl-tests/26-tls13_client_auth.conf
index 55361dd..9c42391 100644
--- a/test/ssl-tests/26-tls13_client_auth.conf
+++ b/test/ssl-tests/26-tls13_client_auth.conf
@@ -299,6 +299,10 @@
 ExpectedClientSignType = RSA-PSS
 ExpectedResult = Success
 HandshakeMode = PostHandshakeAuth
+client = 8-client-auth-TLSv1.3-require-post-handshake-client-extra
+
+[8-client-auth-TLSv1.3-require-post-handshake-client-extra]
+EnablePHA = Yes
 
 
 # ===========================================================
@@ -337,6 +341,10 @@
 ExpectedClientSignType = RSA-PSS
 ExpectedResult = Success
 HandshakeMode = PostHandshakeAuth
+client = 9-client-auth-TLSv1.3-require-non-empty-names-post-handshake-client-extra
+
+[9-client-auth-TLSv1.3-require-non-empty-names-post-handshake-client-extra]
+EnablePHA = Yes
 
 
 # ===========================================================
@@ -369,6 +377,10 @@
 ExpectedResult = ServerFail
 ExpectedServerAlert = UnknownCA
 HandshakeMode = PostHandshakeAuth
+client = 10-client-auth-TLSv1.3-noroot-post-handshake-client-extra
+
+[10-client-auth-TLSv1.3-noroot-post-handshake-client-extra]
+EnablePHA = Yes
 
 
 # ===========================================================
@@ -401,7 +413,7 @@
 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
+EnablePHA = Yes
 
 
 # ===========================================================
@@ -471,6 +483,6 @@
 ForcePHA = Yes
 
 [13-client-auth-TLSv1.3-request-force-both-post-handshake-client-extra]
-ForcePHA = Yes
+EnablePHA = Yes
 
 
diff --git a/test/ssl-tests/26-tls13_client_auth.conf.in b/test/ssl-tests/26-tls13_client_auth.conf.in
index e53cda2..018dd82 100644
--- a/test/ssl-tests/26-tls13_client_auth.conf.in
+++ b/test/ssl-tests/26-tls13_client_auth.conf.in
@@ -176,6 +176,9 @@
             "MaxProtocol" => "TLSv1.3",
             "Certificate" => test_pem("ee-client-chain.pem"),
             "PrivateKey" => test_pem("ee-key.pem"),
+            extra => {
+                "EnablePHA" => "Yes",
+            },
         },
         test => {
             "ExpectedResult" => "Success",
@@ -201,6 +204,9 @@
             "MaxProtocol" => "TLSv1.3",
             "Certificate" => test_pem("ee-client-chain.pem"),
             "PrivateKey" => test_pem("ee-key.pem"),
+            extra => {
+                "EnablePHA" => "Yes",
+            },
         },
         test => {
             "ExpectedResult" => "Success",
@@ -223,6 +229,9 @@
             "MaxProtocol" => "TLSv1.3",
             "Certificate" => test_pem("ee-client-chain.pem"),
             "PrivateKey" => test_pem("ee-key.pem"),
+            extra => {
+                "EnablePHA" => "Yes",
+            },
         },
         test => {
             "ExpectedResult" => "ServerFail",
@@ -240,9 +249,9 @@
         client => {
             "MinProtocol" => "TLSv1.3",
             "MaxProtocol" => "TLSv1.3",
-	    extra => {
-		"ForcePHA" => "Yes",
-	    },
+            extra => {
+                "EnablePHA" => "Yes",
+            },
         },
         test => {
             "ExpectedResult" => "Success",
@@ -255,9 +264,9 @@
             "MinProtocol" => "TLSv1.3",
             "MaxProtocol" => "TLSv1.3",
             "VerifyMode" => "RequestPostHandshake",
-	    extra => {
-		"ForcePHA" => "Yes",
-	    },
+            extra => {
+                "ForcePHA" => "Yes",
+            },
         },
         client => {
             "MinProtocol" => "TLSv1.3",
@@ -274,16 +283,16 @@
             "MinProtocol" => "TLSv1.3",
             "MaxProtocol" => "TLSv1.3",
             "VerifyMode" => "RequestPostHandshake",
-	    extra => {
-		"ForcePHA" => "Yes",
-	    },
+            extra => {
+                "ForcePHA" => "Yes",
+            },
         },
         client => {
             "MinProtocol" => "TLSv1.3",
             "MaxProtocol" => "TLSv1.3",
-	    extra => {
-		"ForcePHA" => "Yes",
-	    },
+            extra => {
+                "EnablePHA" => "Yes",
+            },
         },
         test => {
             "ExpectedResult" => "Success",
diff --git a/test/ssl_test_ctx.c b/test/ssl_test_ctx.c
index cb4b860..7533385 100644
--- a/test/ssl_test_ctx.c
+++ b/test/ssl_test_ctx.c
@@ -629,9 +629,9 @@
 
 IMPLEMENT_SSL_TEST_STRING_OPTION(SSL_TEST_CTX, test, expected_cipher)
 
-/* Client and Server ForcePHA */
+/* Client and Server PHA */
 
-IMPLEMENT_SSL_TEST_BOOL_OPTION(SSL_TEST_CLIENT_CONF, client, force_pha)
+IMPLEMENT_SSL_TEST_BOOL_OPTION(SSL_TEST_CLIENT_CONF, client, enable_pha)
 IMPLEMENT_SSL_TEST_BOOL_OPTION(SSL_TEST_SERVER_CONF, server, force_pha)
 
 /* Known test options and their corresponding parse methods. */
@@ -689,7 +689,7 @@
     { "SRPUser", &parse_client_srp_user },
     { "SRPPassword", &parse_client_srp_password },
     { "MaxFragmentLenExt", &parse_max_fragment_len_mode },
-    { "ForcePHA", &parse_client_force_pha },
+    { "EnablePHA", &parse_client_enable_pha },
 };
 
 /* Nested server options. */
diff --git a/test/ssl_test_ctx.h b/test/ssl_test_ctx.h
index e26c207..86d227d 100644
--- a/test/ssl_test_ctx.h
+++ b/test/ssl_test_ctx.h
@@ -108,8 +108,8 @@
     char *reneg_ciphers;
     char *srp_user;
     char *srp_password;
-    /* Forced PHA */
-    int force_pha;
+    /* PHA enabled */
+    int enable_pha;
 } SSL_TEST_CLIENT_CONF;
 
 typedef struct {
diff --git a/test/sslapitest.c b/test/sslapitest.c
index c65bf59..81761f2 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -1270,7 +1270,7 @@
                 || !TEST_true(SSL_set_session(clientssl, sesscache[i])))
             goto end;
 
-        SSL_force_post_handshake_auth(clientssl);
+        SSL_set_post_handshake_auth(clientssl, 1);
 
         if (!TEST_true(create_ssl_connection(serverssl, clientssl,
                                                     SSL_ERROR_NONE)))
@@ -1377,7 +1377,7 @@
                                           &clientssl, NULL, NULL)))
         goto end;
 
-    SSL_force_post_handshake_auth(clientssl);
+    SSL_set_post_handshake_auth(clientssl, 1);
 
     if (!TEST_true(create_ssl_connection(serverssl, clientssl,
                                                 SSL_ERROR_NONE))
@@ -4336,7 +4336,7 @@
                                       NULL, NULL)))
         goto end;
 
-    SSL_force_post_handshake_auth(clientssl);
+    SSL_set_post_handshake_auth(clientssl, 1);
 
     if (!TEST_true(create_ssl_connection(serverssl, clientssl,
                                          SSL_ERROR_NONE)))
diff --git a/util/libssl.num b/util/libssl.num
index 9b6d266..521637f 100644
--- a/util/libssl.num
+++ b/util/libssl.num
@@ -475,7 +475,7 @@
 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:
+SSL_set_post_handshake_auth             479	1_1_1	EXIST::FUNCTION:
 SSL_export_keying_material_early        480	1_1_1	EXIST::FUNCTION:
 SSL_CTX_use_cert_and_key                481	1_1_1	EXIST::FUNCTION:
 SSL_use_cert_and_key                    482	1_1_1	EXIST::FUNCTION: