Add public API for tls_prf

Add a public API for key derivation, introducing an enum for `tls_prf`
type.
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 766217c..a460e20 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -450,6 +450,18 @@
 }
 mbedtls_ssl_states;
 
+/*
+ * The tls_prf function types.
+ */
+typedef enum
+{
+   MBEDTLS_SSL_TLS_PRF_NONE,
+   MBEDTLS_SSL_TLS_PRF_SSL3,
+   MBEDTLS_SSL_TLS_PRF_TLS1,
+   MBEDTLS_SSL_TLS_PRF_SHA384,
+   MBEDTLS_SSL_TLS_PRF_SHA256
+}
+mbedtls_tls_prf_types;
 /**
  * \brief          Callback type: send data on the network.
  *
@@ -559,25 +571,6 @@
  */
 typedef int mbedtls_ssl_get_timer_t( void * ctx );
 
-/**
- * \brief          Function type: TLS-PRF function.
- *
- * \param secret   Secret for the key derivation function.
- * \param slen     Length of the secret.
- * \param label    String label for the key derivation function,
- *                 terminated with null character.
- * \param random   Random bytes.
- * \param rlen     Length of the random bytes buffer.
- * \param dstbuf   The buffer holding the derived key.
- * \param dlen     Length of the output buffer.
- *
- * \return         0 on sucess. An SSL specific error on failure.
- */
-typedef int  mbedtls_ssl_tls_prf( const unsigned char *secret, size_t slen,
-                                  const char *label,
-                                  const unsigned char *random, size_t rlen,
-                                  unsigned char *dstbuf, size_t dlen );
-
 /* Defined below */
 typedef struct mbedtls_ssl_session mbedtls_ssl_session;
 typedef struct mbedtls_ssl_context mbedtls_ssl_context;
@@ -943,7 +936,7 @@
      *  tls_prf and random bytes. Should replace f_export_keys    */
     int (*f_export_keys_ext)( void *, const unsigned char *,
                 const unsigned char *, size_t, size_t, size_t,
-                mbedtls_ssl_tls_prf *, unsigned char[32], unsigned char[32]);
+                unsigned char[32], unsigned char[32], mbedtls_tls_prf_types );
     void *p_export_keys;            /*!< context for key export callback    */
 #endif
 
@@ -1667,9 +1660,9 @@
  * \param maclen        MAC length.
  * \param keylen        Key length.
  * \param ivlen         IV length.
- * \param tls_prf       The TLS PRF function used in the handshake.
  * \param client_random The client random bytes.
  * \param server_random The server random bytes.
+ * \param tls_prf_type The tls_prf enum type.
  *
  * \return          0 if successful, or
  *                  a specific MBEDTLS_ERR_XXX code.
@@ -1680,9 +1673,9 @@
                                            size_t maclen,
                                            size_t keylen,
                                            size_t ivlen,
-                                           mbedtls_ssl_tls_prf *tls_prf,
                                            unsigned char client_random[32],
-                                           unsigned char server_random[32] );
+                                           unsigned char server_random[32],
+                                           mbedtls_tls_prf_types tls_prf_type );
 #endif /* MBEDTLS_SSL_EXPORT_KEYS */
 
 /**
@@ -3560,6 +3553,27 @@
  */
 void mbedtls_ssl_session_free( mbedtls_ssl_session *session );
 
+/**
+ * \brief          TLS-PRF function for key derivation.
+ *
+ * \param prf      The tls_prf type funtion type to be used.
+ * \param secret   Secret for the key derivation function.
+ * \param slen     Length of the secret.
+ * \param label    String label for the key derivation function,
+ *                 terminated with null character.
+ * \param random   Random bytes.
+ * \param rlen     Length of the random bytes buffer.
+ * \param dstbuf   The buffer holding the derived key.
+ * \param dlen     Length of the output buffer.
+ *
+ * \return         0 on sucess. An SSL specific error on failure.
+ */
+int  mbedtls_ssl_tls_prf( const mbedtls_tls_prf_types prf,
+                          const unsigned char *secret, size_t slen,
+                          const char *label,
+                          const unsigned char *random, size_t rlen,
+                          unsigned char *dstbuf, size_t dlen );
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h
index ac4d96d..9c4be53 100644
--- a/include/mbedtls/ssl_internal.h
+++ b/include/mbedtls/ssl_internal.h
@@ -276,6 +276,10 @@
 #endif /* MBEDTLS_SSL_PROTO_TLS1_2 &&
           MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */
 
+typedef int  mbedtls_ssl_tls_prf_cb( const unsigned char *secret, size_t slen,
+                                     const char *label,
+                                     const unsigned char *random, size_t rlen,
+                                     unsigned char *dstbuf, size_t dlen );
 /*
  * This structure contains the parameters only needed during handshake.
  */
@@ -425,9 +429,7 @@
     void (*update_checksum)(mbedtls_ssl_context *, const unsigned char *, size_t);
     void (*calc_verify)(mbedtls_ssl_context *, unsigned char *);
     void (*calc_finished)(mbedtls_ssl_context *, unsigned char *, int);
-    int  (*tls_prf)(const unsigned char *, size_t, const char *,
-                    const unsigned char *, size_t,
-                    unsigned char *, size_t);
+    mbedtls_ssl_tls_prf_cb *tls_prf;
 
     mbedtls_ssl_ciphersuite_t const *ciphersuite_info;
 
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 620adf9..df106a5 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -751,6 +751,43 @@
 #endif /* MBEDTLS_USE_PSA_CRYPTO &&
           MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */
 
+int  mbedtls_ssl_tls_prf( const mbedtls_tls_prf_types prf,
+                          const unsigned char *secret, size_t slen,
+                          const char *label,
+                          const unsigned char *random, size_t rlen,
+                          unsigned char *dstbuf, size_t dlen )
+{
+    mbedtls_ssl_tls_prf_cb *tls_prf = NULL;
+
+    switch( prf )
+    {
+#if defined(MBEDTLS_SSL_PROTO_SSL3)
+        case MBEDTLS_SSL_TLS_PRF_SSL3:
+            tls_prf = ssl3_prf;
+        break;
+#endif
+#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1)
+        case MBEDTLS_SSL_TLS_PRF_TLS1:
+            tls_prf = tls1_prf;
+        break;
+#endif
+#if defined(MBEDTLS_SHA512_C)
+        case MBEDTLS_SSL_TLS_PRF_SHA384:
+            tls_prf = tls_prf_sha384;
+        break;
+#endif
+#if defined(MBEDTLS_SHA256_C)
+        case MBEDTLS_SSL_TLS_PRF_SHA256:
+            tls_prf = tls_prf_sha256;
+        break;
+#endif
+    default:
+        return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
+    }
+
+    return( tls_prf( secret, slen, label, random, rlen, dstbuf, dlen ) );
+}
+
 int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl )
 {
     int ret = 0;
@@ -774,6 +811,10 @@
      * "The master secret is always exactly 48 bytes in length." */
     size_t const master_secret_len = 48;
 
+#if defined(MBEDTLS_SSL_EXPORT_KEYS)
+    mbedtls_tls_prf_types tls_prf_type = MBEDTLS_SSL_TLS_PRF_NONE;
+#endif
+
 #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
     unsigned char session_hash[48];
 #endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */
@@ -815,6 +856,9 @@
         handshake->tls_prf = ssl3_prf;
         handshake->calc_verify = ssl_calc_verify_ssl;
         handshake->calc_finished = ssl_calc_finished_ssl;
+#if defined(MBEDTLS_SSL_EXPORT_KEYS)
+        tls_prf_type = MBEDTLS_SSL_TLS_PRF_SSL3;
+#endif
     }
     else
 #endif
@@ -824,6 +868,9 @@
         handshake->tls_prf = tls1_prf;
         handshake->calc_verify = ssl_calc_verify_tls;
         handshake->calc_finished = ssl_calc_finished_tls;
+#if defined(MBEDTLS_SSL_EXPORT_KEYS)
+        tls_prf_type = MBEDTLS_SSL_TLS_PRF_TLS1;
+#endif
     }
     else
 #endif
@@ -835,6 +882,9 @@
         handshake->tls_prf = tls_prf_sha384;
         handshake->calc_verify = ssl_calc_verify_tls_sha384;
         handshake->calc_finished = ssl_calc_finished_tls_sha384;
+#if defined(MBEDTLS_SSL_EXPORT_KEYS)
+        tls_prf_type = MBEDTLS_SSL_TLS_PRF_SHA384;
+#endif
     }
     else
 #endif
@@ -844,6 +894,9 @@
         handshake->tls_prf = tls_prf_sha256;
         handshake->calc_verify = ssl_calc_verify_tls_sha256;
         handshake->calc_finished = ssl_calc_finished_tls_sha256;
+#if defined(MBEDTLS_SSL_EXPORT_KEYS)
+        tls_prf_type = MBEDTLS_SSL_TLS_PRF_SHA256;
+#endif
     }
     else
 #endif
@@ -1271,9 +1324,10 @@
         ssl->conf->f_export_keys_ext( ssl->conf->p_export_keys,
                                       session->master, keyblk,
                                       mac_key_len, keylen,
-                                      iv_copy_len, handshake->tls_prf,
+                                      iv_copy_len,
                                       handshake->randbytes + 32,
-                                      handshake->randbytes );
+                                      handshake->randbytes,
+                                      tls_prf_type);
     }
 #endif
 
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 353a580..a9bcd01 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -466,7 +466,7 @@
 {
     unsigned char master_secret[48];
     unsigned char randbytes[64];
-    mbedtls_ssl_tls_prf *tls_prf;
+    mbedtls_tls_prf_types tls_prf_type;
 } eap_tls_keys;
 
 static int eap_tls_key_derivation ( void *p_expkey,
@@ -475,9 +475,9 @@
                                     size_t maclen,
                                     size_t keylen,
                                     size_t ivlen,
-                                    mbedtls_ssl_tls_prf *tls_prf,
                                     unsigned char client_random[32],
-                                    unsigned char server_random[32] )
+                                    unsigned char server_random[32],
+                                    mbedtls_tls_prf_types tls_prf_type )
 {
     eap_tls_keys *keys = (eap_tls_keys *)p_expkey;
 
@@ -488,7 +488,7 @@
     memcpy( keys->master_secret, ms, sizeof( keys->master_secret ) );
     memcpy( keys->randbytes, client_random, 32 );
     memcpy( keys->randbytes + 32, server_random, 32 );
-    keys->tls_prf = tls_prf;
+    keys->tls_prf_type = tls_prf_type;
 
     return( 0 );
 }
@@ -1979,17 +1979,25 @@
 #endif
 
 #if defined(MBEDTLS_SSL_EXPORT_KEYS)
-    if( opt.eap_tls != 0 &&
-        eap_tls_keying.tls_prf != NULL )
+    if( opt.eap_tls != 0  )
     {
         size_t j = 0;
-        eap_tls_keying.tls_prf( eap_tls_keying.master_secret,
-                                sizeof( eap_tls_keying.master_secret ),
-                                eap_tls_label,
-                                eap_tls_keying.randbytes,
-                                sizeof( eap_tls_keying.randbytes ),
-                                eap_tls_keymaterial,
-                                sizeof( eap_tls_keymaterial ) );
+
+        if( ( ret = mbedtls_ssl_tls_prf( eap_tls_keying.tls_prf_type,
+                                         eap_tls_keying.master_secret,
+                                         sizeof( eap_tls_keying.master_secret ),
+                                         eap_tls_label,
+                                         eap_tls_keying.randbytes,
+                                         sizeof( eap_tls_keying.randbytes ),
+                                         eap_tls_keymaterial,
+                                         sizeof( eap_tls_keymaterial ) ) )
+                                         != 0 )
+        {
+            mbedtls_printf( " failed\n  ! mbedtls_ssl_tls_prf returned -0x%x\n\n",
+                            -ret );
+            goto exit;
+        }
+
         mbedtls_printf( "    EAP-TLS key material is:" );
         for( j = 0; j < sizeof( eap_tls_keymaterial ); j++ )
         {
@@ -1999,9 +2007,18 @@
         }
         mbedtls_printf("\n");
 
-        eap_tls_keying.tls_prf( NULL, 0, eap_tls_label, eap_tls_keying.randbytes,
-                                sizeof( eap_tls_keying.randbytes ), eap_tls_iv,
-                                sizeof( eap_tls_iv  ) );
+        if( ( ret = mbedtls_ssl_tls_prf( eap_tls_keying.tls_prf_type, NULL, 0,
+                                          eap_tls_label,
+                                          eap_tls_keying.randbytes,
+                                          sizeof( eap_tls_keying.randbytes ),
+                                          eap_tls_iv,
+                                          sizeof( eap_tls_iv ) ) ) != 0 )
+         {
+             mbedtls_printf( " failed\n  ! mbedtls_ssl_tls_prf returned -0x%x\n\n",
+                             -ret );
+             goto exit;
+         }
+
         mbedtls_printf( "    EAP-TLS IV is:" );
         for( j = 0; j < sizeof( eap_tls_iv ); j++ )
         {
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 54e2e51..363b2dc 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -582,7 +582,7 @@
 {
     unsigned char master_secret[48];
     unsigned char randbytes[64];
-    mbedtls_ssl_tls_prf *tls_prf;
+    mbedtls_tls_prf_types tls_prf_type;
 } eap_tls_keys;
 
 static int eap_tls_key_derivation ( void *p_expkey,
@@ -591,9 +591,9 @@
                                     size_t maclen,
                                     size_t keylen,
                                     size_t ivlen,
-                                    mbedtls_ssl_tls_prf *tls_prf,
                                     unsigned char client_random[32],
-                                    unsigned char server_random[32] )
+                                    unsigned char server_random[32],
+                                    mbedtls_tls_prf_types tls_prf_type )
 {
     eap_tls_keys *keys = (eap_tls_keys *)p_expkey;
 
@@ -604,7 +604,7 @@
     memcpy( keys->master_secret, ms, sizeof( keys->master_secret ) );
     memcpy( keys->randbytes, client_random, 32 );
     memcpy( keys->randbytes + 32, server_random, 32 );
-    keys->tls_prf = tls_prf;
+    keys->tls_prf_type = tls_prf_type;
 
     return( 0 );
 }
@@ -3180,17 +3180,25 @@
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
 #if defined(MBEDTLS_SSL_EXPORT_KEYS)
-    if( opt.eap_tls != 0 &&
-        eap_tls_keying.tls_prf != NULL )
+    if( opt.eap_tls != 0 )
     {
         size_t j = 0;
-        eap_tls_keying.tls_prf( eap_tls_keying.master_secret,
-                                sizeof( eap_tls_keying.master_secret ),
-                                eap_tls_label,
-                                eap_tls_keying.randbytes,
-                                sizeof( eap_tls_keying.randbytes ),
-                                eap_tls_keymaterial,
-                                sizeof( eap_tls_keymaterial ) );
+
+        if( ( ret = mbedtls_ssl_tls_prf( eap_tls_keying.tls_prf_type,
+                                         eap_tls_keying.master_secret,
+                                         sizeof( eap_tls_keying.master_secret ),
+                                         eap_tls_label,
+                                         eap_tls_keying.randbytes,
+                                         sizeof( eap_tls_keying.randbytes ),
+                                         eap_tls_keymaterial,
+                                         sizeof( eap_tls_keymaterial ) ) )
+                                         != 0 )
+        {
+            mbedtls_printf( " failed\n  ! mbedtls_ssl_tls_prf returned -0x%x\n\n",
+                            -ret );
+            goto exit;
+        }
+
         mbedtls_printf( "    EAP-TLS key material is:" );
         for( j = 0; j < sizeof( eap_tls_keymaterial ); j++ )
         {
@@ -3200,9 +3208,18 @@
         }
         mbedtls_printf("\n");
 
-        eap_tls_keying.tls_prf( NULL, 0, eap_tls_label, eap_tls_keying.randbytes,
-                                sizeof( eap_tls_keying.randbytes ), eap_tls_iv,
-                                sizeof( eap_tls_iv  ) );
+        if( ( ret = mbedtls_ssl_tls_prf( eap_tls_keying.tls_prf_type, NULL, 0,
+                                          eap_tls_label,
+                                          eap_tls_keying.randbytes,
+                                          sizeof( eap_tls_keying.randbytes ),
+                                          eap_tls_iv,
+                                          sizeof( eap_tls_iv ) ) ) != 0 )
+         {
+             mbedtls_printf( " failed\n  ! mbedtls_ssl_tls_prf returned -0x%x\n\n",
+                             -ret );
+             goto exit;
+         }
+
         mbedtls_printf( "    EAP-TLS IV is:" );
         for( j = 0; j < sizeof( eap_tls_iv ); j++ )
         {