PolarSSL is now part of ARM Official announcement and rebranded as mbed TLS.

handling certificate request


Apr 4, 2013 08:32
Billy

Hello,

In the processing of the request of client certificate (ssl_parse_certificate_request) there is a validation of the message, but the treatment is not present (dn is not saved anywhere, thus I can not determine which certificate is requested by the server). Do you have plans implementing this functionality?

Best Regards,

 
Apr 4, 2013 15:25
Paul Bakker

You mean that you would like to receive a callback with the DN's requested by the server so you can set the client certificate at that point in time?

 
Apr 5, 2013 08:35
Billy

Yeap, In a case of https in browsers using personal certificates: server gives DN's, after that browser let you choose one of previously imported personal certificate.

 
Apr 11, 2013 09:49
Billy

Answer me, please. Sorry for molestation, and for my English =).

 
Apr 11, 2013 10:07
Paul Bakker

You are forgiven ;)

Sounds like something that should be added.

I'll make sure it gets in the 1.2 branch and the current development branch. (Possible also as a backport to the 1.1 branch)

 
Apr 12, 2013 08:30
Billy

Thanks you =)

 
Apr 12, 2013 09:23
Paul Bakker

After implementing the feature, I have to take back the previous statement.

Basic functionality where the library executes a callback with the DN back to the application is easy to implement, but does not give access to the certificate_types and supported_signature_algorithms that the server is providing and expecting as well. We see no clean way of implementing this in the 1.2 branch without having to alter existing structures.

For inclusion in the base, we'd rather do it well or not at all.

In the development / 1.3 branch we are able to add it in a cleaner way due to other improvements that the branch received.

As a result it seems that inclusion in the 1.2 branch as a standard feature is not going to happen.

Still, if you want to apply the patch yourself to 1.2 with basic functionality, knowing that you will have to change to a different callback prototype in the future, here is the patch for the 1.2 branch:

diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h
index 9746e27..b39e64f 100644
--- a/include/polarssl/ssl.h
+++ b/include/polarssl/ssl.h
@@ -413,6 +413,7 @@ struct _ssl_context
     int (*f_get_cache)(void *, ssl_session *);
     int (*f_set_cache)(void *, const ssl_session *);
     int (*f_sni)(void *, ssl_context *, const unsigned char *, size_t);
+    int (*f_cli_cert)(void *, ssl_context *, const x509_name *);

     void *p_rng;                /*!< context for the RNG function     */
     void *p_dbg;                /*!< context for the debug function   */
@@ -423,6 +424,7 @@ struct _ssl_context
     void *p_set_cache;          /*!< context for cache store          */
     void *p_sni;                /*!< context for SNI extension        */
     void *p_hw_data;            /*!< context for HW acceleration      */
+    void *p_cli_cert;           /*!< context for client certificates  */

     /*
      * Session layer
@@ -837,6 +839,33 @@ void ssl_set_sni( ssl_context *ssl,
                   void *p_sni );

 /**
+ * \brief          Set client side certificate selection callback
+ *                 (optional, client-side only).
+ *
+ *                 If set, the client certificate selection callback is called
+ *                 whenever the client received a CertificateRequest handshake
+ *                 message from the server. The callback is called once for
+ *                 each DN that is in the list of acceptable DNs.
+ *
+ *                 The client certificate selection callback has the
+ *                 following parameters: (void *parameter, ssl_context *ssl,
+ *                 const x509_name *dn). If a suitable certificate is found
+ *                 the callback should set the certificate and key to use
+ *                 with ssl_set_own_cert() (and possibly adjust the CA chain
+ *                 as well) and return 0. The callback should return 1 if no
+ *                 certificate was changes and the callback should return -1
+ *                 to abort the handshake at this point.
+ *
+ * \param ssl      SSL context
+ * \param f_cli_cert  client certificate selection function
+ * \param p_cli_cert  client certificate selection parameter
+ */
+void ssl_set_cli_cert( ssl_context *ssl,
+                       int (*f_cli_cert)(void *, ssl_context *,
+                                         const x509_name * ),
+                       void *p_cli_cert );
+
+/**
  * \brief          Set the maximum supported version sent from the client side
  *
  * \param ssl      SSL context
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
index 545906a..1b782e8 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -890,12 +890,18 @@ static int ssl_parse_server_key_exchange( ssl_context *ssl )
 #endif
 }

+int x509_get_name( unsigned char **p,
+                   const unsigned char *end,
+                   x509_name *cur );
+
 static int ssl_parse_certificate_request( ssl_context *ssl )
 {
-    int ret;
-    unsigned char *buf, *p;
+    int ret, cert_selected = 0;
+    unsigned char *buf, *p, *end;
     size_t n = 0, m = 0;
     size_t cert_type_len = 0, sig_alg_len = 0, dn_len = 0;
+    size_t item_len = 0, name_len = 0;
+    x509_name dn_name;

     SSL_DEBUG_MSG( 2, ( "=> parse certificate request" ) );

@@ -988,8 +994,70 @@ static int ssl_parse_certificate_request( ssl_context *ssl )

     dn_len = ( ( buf[5 + m + n] <<  8 )
              | ( buf[6 + m + n]       ) );
+    p = buf + 7 + m + n;
+
+    while( dn_len > 0 )
+    {
+        memset( &dn_name, 0x00, sizeof(x509_name) );
+
+        if( dn_len < 2 )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
+            return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST );
+        }
+
+        item_len = ( ( (*(p    )) <<  8 )
+                   | ( (*(p + 1))       ) );
+        p += 2;
+        end = p + item_len;
+
+        if( item_len + 2 > dn_len )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
+            return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST );
+        }
+
+        if( ( ret = asn1_get_tag( &p, end, &name_len,
+                                  ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
+            return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST + ret );
+        }
+
+        if( name_len + 2 != item_len )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
+            return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST );
+        }
+
+        if( ( ret = x509_get_name( &p, end, &dn_name ) ) != 0 )
+        {
+            SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
+            return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST );
+        }
+
+        m += 2 + item_len;
+        dn_len -= 2 + item_len;
+
+        if( ssl->f_cli_cert != NULL && cert_selected == 0 )
+        {
+            // Call the client certificate callback to let the application
+            // set the appropriate client certificate
+            //
+            ret = ssl->f_cli_cert( ssl->p_cli_cert, ssl, &dn_name );
+            if( ret == 1 )
+                continue;
+
+            if( ret != 0 )
+            {
+                if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 )
+                    return( ret );
+            }
+
+            cert_selected = 1;
+        }
+    }

-    n += dn_len;
     if( ssl->in_hslen != 7 + m + n )
     {
         SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
diff --git a/library/x509parse.c b/library/x509parse.c
index bac0e93..f5fd10a 100644
--- a/library/x509parse.c
+++ b/library/x509parse.c
@@ -272,7 +272,7 @@ static int x509_get_attr_type_value( unsigned char **p,
  *
  *  AttributeValue ::= ANY DEFINED BY AttributeType
  */
-static int x509_get_name( unsigned char **p,
+int x509_get_name( unsigned char **p,
                           const unsigned char *end,
                           x509_name *cur )
 {
 
Jan 12, 2016 16:28
Johan Pascal

Hi,

sorry to post in this very old thread but did it made it's way to polarssl 1.3 or mbedtls2.x?

I can't find it and it is something I need. I guess I could use a workaround by using ssl_handshake_step and checking the ssl_context.state value after each step but it would be nicer to have a callback and use ssl_handshake without going to check for the internal state...

thanks

Johan

 
Jan 12, 2016 17:52
Manuel Pégourié-Gonnard

I'm afraid we haven't implemented that callback yet, and I don't think it's in our short-term plans either, sorry. Do you think you would be able to submit a pull request (perhaps based on Paul's suggested patch above)?