Test accessors to config DN hints for cert request

Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com>
diff --git a/library/ssl_tls12_client.c b/library/ssl_tls12_client.c
index f516efa..35f11ea 100644
--- a/library/ssl_tls12_client.c
+++ b/library/ssl_tls12_client.c
@@ -2534,6 +2534,7 @@
     size_t sig_alg_len;
 #if defined(MBEDTLS_DEBUG_C)
         unsigned char *sig_alg;
+        unsigned char *dn;
 #endif
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate request" ) );
@@ -2681,6 +2682,43 @@
         return( MBEDTLS_ERR_SSL_DECODE_ERROR );
     }
 
+#if defined(MBEDTLS_DEBUG_C)
+    dn = buf + mbedtls_ssl_hs_hdr_len( ssl ) + 3 + n - dn_len;
+    for( size_t i = 0, dni_len = 0; i < dn_len; i += 2 + dni_len )
+    {
+        unsigned char *p = dn + i + 2;
+        mbedtls_x509_name name;
+        mbedtls_x509_name *name_cur, *name_prv;
+        size_t asn1_len;
+        char s[MBEDTLS_X509_MAX_DN_NAME_SIZE];
+        memset( &name, 0, sizeof( name ) );
+        dni_len = MBEDTLS_GET_UINT16_BE( dn + i, 0 );
+        if( dni_len > dn_len - i - 2 ||
+            mbedtls_asn1_get_tag( &p, p + dni_len, &asn1_len,
+              MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) != 0 ||
+            mbedtls_x509_get_name( &p, p + asn1_len, &name ) != 0 )
+        {
+            MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
+            mbedtls_ssl_send_alert_message(
+                ssl,
+                MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+            return( MBEDTLS_ERR_SSL_DECODE_ERROR );
+        }
+        MBEDTLS_SSL_DEBUG_MSG( 3,
+            ( "DN hint: %.*s",
+              mbedtls_x509_dn_gets( s, sizeof(s), &name ), s ) );
+        name_cur = name.next;
+        while( name_cur != NULL )
+        {
+            name_prv = name_cur;
+            name_cur = name_cur->next;
+            mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) );
+            mbedtls_free( name_prv );
+        }
+    }
+#endif
+
 exit:
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate request" ) );
 
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 4251817..5231fe4 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -116,6 +116,7 @@
 #define DFL_CID_VALUE_RENEGO    NULL
 #define DFL_AUTH_MODE           -1
 #define DFL_CERT_REQ_CA_LIST    MBEDTLS_SSL_CERT_REQ_CA_LIST_ENABLED
+#define DFL_CERT_REQ_DN_HINT    0
 #define DFL_MFL_CODE            MBEDTLS_SSL_MAX_FRAG_LEN_NONE
 #define DFL_TRUNC_HMAC          -1
 #define DFL_TICKETS             MBEDTLS_SSL_SESSION_TICKETS_ENABLED
@@ -506,6 +507,7 @@
     "                        options: none, optional, required\n" \
     "    cert_req_ca_list=%%d default: 1 (send ca list)\n"  \
     "                        options: 1 (send ca list), 0 (don't send)\n" \
+    "                                 2 (send conf dn hint), 3 (send hs dn hint)\n" \
     USAGE_IO                                                \
     USAGE_KEY_OPAQUE                                        \
     "\n"                                                    \
@@ -629,6 +631,7 @@
     int allow_sha1;             /* flag for SHA-1 support                   */
     int auth_mode;              /* verify mode for connection               */
     int cert_req_ca_list;       /* should we send the CA list?              */
+    int cert_req_dn_hint;       /* mode to set DN hints for CA list to send */
     unsigned char mfl_code;     /* code for maximum fragment length         */
     int trunc_hmac;             /* accept truncated hmac?                   */
     int tickets;                /* enable / disable session tickets         */
@@ -1597,6 +1600,7 @@
     opt.allow_sha1          = DFL_SHA1;
     opt.auth_mode           = DFL_AUTH_MODE;
     opt.cert_req_ca_list    = DFL_CERT_REQ_CA_LIST;
+    opt.cert_req_dn_hint    = DFL_CERT_REQ_DN_HINT;
     opt.mfl_code            = DFL_MFL_CODE;
     opt.trunc_hmac          = DFL_TRUNC_HMAC;
     opt.tickets             = DFL_TICKETS;
@@ -1923,8 +1927,13 @@
         else if( strcmp( p, "cert_req_ca_list" ) == 0 )
         {
             opt.cert_req_ca_list = atoi( q );
-            if( opt.cert_req_ca_list < 0 || opt.cert_req_ca_list > 1 )
+            if( opt.cert_req_ca_list < 0 || opt.cert_req_ca_list > 3 )
                 goto usage;
+            if( opt.cert_req_ca_list > 1 )
+            {
+                opt.cert_req_dn_hint = opt.cert_req_ca_list;
+                opt.cert_req_ca_list = MBEDTLS_SSL_CERT_REQ_CA_LIST_ENABLED;
+            }
         }
         else if( strcmp( p, "max_frag_len" ) == 0 )
         {
@@ -2732,6 +2741,16 @@
     if( opt.cert_req_ca_list != DFL_CERT_REQ_CA_LIST )
         mbedtls_ssl_conf_cert_req_ca_list( &conf, opt.cert_req_ca_list );
 
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED)
+    /* exercise setting DN hints for server certificate request
+     * (Intended for use where the client cert expected has been signed by
+     *  a specific CA which is an intermediate in a CA chain, not the root) */
+    if( opt.cert_req_dn_hint == 2 && key_cert_init2 )
+        mbedtls_ssl_conf_dn_hints( &conf, &srvcert2 );
+#endif
+#endif
+
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
     if( opt.hs_to_min != DFL_HS_TO_MIN || opt.hs_to_max != DFL_HS_TO_MAX )
         mbedtls_ssl_conf_handshake_timeout( &conf, opt.hs_to_min, opt.hs_to_max );
@@ -3332,6 +3351,20 @@
     }
 #endif
 
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
+#if defined(MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED)
+    /* exercise setting DN hints for server certificate request
+     * (Intended for use where the client cert expected has been signed by
+     *  a specific CA which is an intermediate in a CA chain, not the root)
+     * (Additionally, the CA choice would typically be influenced by SNI
+     *  if being set per-handshake using mbedtls_ssl_set_hs_dn_hints()) */
+    if( opt.cert_req_dn_hint == 3 && key_cert_init2 )
+        mbedtls_ssl_set_hs_dn_hints( &ssl, &srvcert2 );
+#endif
+#endif
+#endif
+
     mbedtls_printf( " ok\n" );
 
     /*
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 0b6711c..f50d986 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -5116,6 +5116,39 @@
             -c "! mbedtls_ssl_handshake returned" \
             -s "X509 - Certificate verification failed"
 
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+run_test    "Authentication: send alt conf DN hints in CertificateRequest" \
+            "$P_SRV debug_level=3 auth_mode=optional cert_req_ca_list=2 \
+             crt_file2=data_files/server1.crt \
+             key_file2=data_files/server1.key" \
+            "$P_CLI debug_level=3 auth_mode=optional \
+             crt_file=data_files/server6.crt \
+             key_file=data_files/server6.key" \
+            0 \
+            -c "DN hint: C=NL, O=PolarSSL, CN=PolarSSL Server 1"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+run_test    "Authentication: send alt conf DN hints in CertificateRequest (2)" \
+            "$P_SRV debug_level=3 auth_mode=optional cert_req_ca_list=2 \
+             crt_file2=data_files/server2.crt \
+             key_file2=data_files/server2.key" \
+            "$P_CLI debug_level=3 auth_mode=optional \
+             crt_file=data_files/server6.crt \
+             key_file=data_files/server6.key" \
+            0 \
+            -c "DN hint: C=NL, O=PolarSSL, CN=localhost"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+run_test    "Authentication: send alt hs DN hints in CertificateRequest" \
+            "$P_SRV debug_level=3 auth_mode=optional cert_req_ca_list=3 \
+             crt_file2=data_files/server1.crt \
+             key_file2=data_files/server1.key" \
+            "$P_CLI debug_level=3 auth_mode=optional \
+             crt_file=data_files/server6.crt \
+             key_file=data_files/server6.key" \
+            0 \
+            -c "DN hint: C=NL, O=PolarSSL, CN=PolarSSL Server 1"
+
 # Tests for auth_mode, using CA callback, these are duplicated from the authentication tests
 # When updating these tests, modify the matching authentication tests accordingly