]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
TLS: Split tls_connection_prf() into two functions
authorDavid Benjamin <davidben@google.com>
Mon, 16 May 2016 15:47:37 +0000 (11:47 -0400)
committerJouni Malinen <j@w1.fi>
Mon, 23 May 2016 17:40:12 +0000 (20:40 +0300)
Most protocols extracting keys from TLS use RFC 5705 exporters which is
commonly implemented in TLS libraries. This is the mechanism used by
EAP-TLS. (EAP-TLS actually predates RFC 5705, but RFC 5705 was defined
to be compatible with it.)

EAP-FAST, however, uses a legacy mechanism. It reuses the TLS internal
key block derivation and derives key material after the key block. This
is uncommon and a misuse of TLS internals, so not all TLS libraries
support this. Instead, we reimplement the PRF for the OpenSSL backend
and don't support it at all in the GnuTLS one.

Since these two are very different operations, split
tls_connection_prf() in two. tls_connection_export_key() implements the
standard RFC 5705 mechanism that we expect most TLS libraries to
support. tls_connection_get_eap_fast_key() implements the
EAP-FAST-specific legacy mechanism which may not be implemented on all
backends but is only used by EAP-FAST.

Signed-Off-By: David Benjamin <davidben@google.com>
src/crypto/tls.h
src/crypto/tls_gnutls.c
src/crypto/tls_internal.c
src/crypto/tls_none.c
src/crypto/tls_openssl.c
src/eap_common/eap_fast_common.c
src/eap_common/eap_fast_common.h
src/eap_peer/eap_fast.c
src/eap_peer/eap_tls_common.c
src/eap_server/eap_server_fast.c
src/eap_server/eap_server_tls_common.c

index 15a3bcfb248342860bb19a2c68f901f9f9493e04..11d504a97fc05465f37e0850f1832ef9f5468bf0 100644 (file)
@@ -336,29 +336,36 @@ int __must_check tls_connection_get_random(void *tls_ctx,
                                         struct tls_random *data);
 
 /**
- * tls_connection_prf - Use TLS-PRF to derive keying material
+ * tls_connection_export_key - Derive keying material from a TLS connection
  * @tls_ctx: TLS context data from tls_init()
  * @conn: Connection context data from tls_connection_init()
  * @label: Label (e.g., description of the key) for PRF
- * @server_random_first: seed is 0 = client_random|server_random,
- * 1 = server_random|client_random
- * @skip_keyblock: Skip TLS key block from the beginning of PRF output
  * @out: Buffer for output data from TLS-PRF
  * @out_len: Length of the output buffer
  * Returns: 0 on success, -1 on failure
  *
- * tls_connection_prf() is required so that further keying material can be
- * derived from the master secret. Example implementation of this function is in
- * tls_prf_sha1_md5() when it is called with seed set to
- * client_random|server_random (or server_random|client_random). For TLSv1.2 and
- * newer, a different PRF is needed, though.
+ * Exports keying material using the mechanism described in RFC 5705.
  */
-int __must_check  tls_connection_prf(void *tls_ctx,
-                                    struct tls_connection *conn,
-                                    const char *label,
-                                    int server_random_first,
-                                    int skip_keyblock,
-                                    u8 *out, size_t out_len);
+int __must_check tls_connection_export_key(void *tls_ctx,
+                                          struct tls_connection *conn,
+                                          const char *label,
+                                          u8 *out, size_t out_len);
+
+/**
+ * tls_connection_get_eap_fast_key - Derive key material for EAP-FAST
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @out: Buffer for output data from TLS-PRF
+ * @out_len: Length of the output buffer
+ * Returns: 0 on success, -1 on failure
+ *
+ * Exports key material after the normal TLS key block for use with
+ * EAP-FAST. Most callers will want tls_connection_export_key(), but EAP-FAST
+ * uses a different legacy mechanism.
+ */
+int __must_check tls_connection_get_eap_fast_key(void *tls_ctx,
+                                                struct tls_connection *conn,
+                                                u8 *out, size_t out_len);
 
 /**
  * tls_connection_handshake - Process TLS handshake (client side)
index c4cd3c1a5f0f4caf24a9efe035458ebf195075d5..200f0eda931af9085288f392870dfb2f90bfd574 100644 (file)
@@ -810,15 +810,22 @@ int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
 }
 
 
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
-                      const char *label, int server_random_first,
-                      int skip_keyblock, u8 *out, size_t out_len)
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+                             const char *label, u8 *out, size_t out_len)
 {
-       if (conn == NULL || conn->session == NULL || skip_keyblock)
+       if (conn == NULL || conn->session == NULL)
                return -1;
 
        return gnutls_prf(conn->session, os_strlen(label), label,
-                         server_random_first, 0, NULL, out_len, (char *) out);
+                         0 /* client_random first */, 0, NULL, out_len,
+                         (char *) out);
+}
+
+
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+                                   u8 *out, size_t out_len)
+{
+       return -1;
 }
 
 
index 01a7c97de3e611c15cbe8ec24cb51603a045815f..c7cb5ded331f2dcaec6df3dfe3fc7f3425228659 100644 (file)
@@ -394,9 +394,9 @@ static int tls_get_keyblock_size(struct tls_connection *conn)
 }
 
 
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
-                      const char *label, int server_random_first,
-                      int skip_keyblock, u8 *out, size_t out_len)
+static int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+                             const char *label, int server_random_first,
+                             int skip_keyblock, u8 *out, size_t out_len)
 {
        int ret = -1, skip = 0;
        u8 *tmp_out = NULL;
@@ -434,6 +434,21 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
 }
 
 
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+                             const char *label, u8 *out, size_t out_len)
+{
+       return tls_connection_prf(tls_ctx, conn, label, 0, 0, out, out_len);
+}
+
+
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+                                   u8 *out, size_t out_len)
+{
+       return tls_connection_prf(tls_ctx, conn, "key expansion", 1, 1, out,
+                                 out_len);
+}
+
+
 struct wpabuf * tls_connection_handshake(void *tls_ctx,
                                         struct tls_connection *conn,
                                         const struct wpabuf *in_data,
index ae392ad8aa0f56bcb819cf5276c567984a1ad112..dd5681e9ca3c3871fc1d5c1f808e26cbcee4b365 100644 (file)
@@ -86,9 +86,15 @@ int tls_connection_get_random(void *tls_ctx, struct tls_connection *conn,
 }
 
 
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
-                      const char *label, int server_random_first,
-                      int skip_keyblock, u8 *out, size_t out_len)
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+                             const char *label, u8 *out, size_t out_len)
+{
+       return -1;
+}
+
+
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+                                   u8 *out, size_t out_len)
 {
        return -1;
 }
index 8c9ecc59c5e941abaf751dbd18dda641807d47ea..994c0d5e3c5aca72e87f5800c378a7baceff25ea 100644 (file)
@@ -3146,9 +3146,19 @@ static int openssl_get_keyblock_size(SSL *ssl)
 #endif /* CONFIG_FIPS */
 
 
-static int openssl_tls_prf(struct tls_connection *conn,
-                          const char *label, int server_random_first,
-                          int skip_keyblock, u8 *out, size_t out_len)
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+                             const char *label, u8 *out, size_t out_len)
+{
+       if (!conn ||
+           SSL_export_keying_material(conn->ssl, out, out_len, label,
+                                      os_strlen(label), NULL, 0, 0) != 1)
+               return -1;
+       return 0;
+}
+
+
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+                                   u8 *out, size_t out_len)
 {
 #ifdef CONFIG_FIPS
        wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS "
@@ -3169,9 +3179,9 @@ static int openssl_tls_prf(struct tls_connection *conn,
        const char *ver;
 
        /*
-        * TLS library did not support key generation, so get the needed TLS
-        * session parameters and use an internal implementation of TLS PRF to
-        * derive the key.
+        * TLS library did not support EAP-FAST key generation, so get the
+        * needed TLS session parameters and use an internal implementation of
+        * TLS PRF to derive the key.
         */
 
        if (conn == NULL)
@@ -3184,15 +3194,13 @@ static int openssl_tls_prf(struct tls_connection *conn,
        if (!ver || !sess)
                return -1;
 
-       if (skip_keyblock) {
-               skip = openssl_get_keyblock_size(ssl);
-               if (skip < 0)
-                       return -1;
-               tmp_out = os_malloc(skip + out_len);
-               if (!tmp_out)
-                       return -1;
-               _out = tmp_out;
-       }
+       skip = openssl_get_keyblock_size(ssl);
+       if (skip < 0)
+               return -1;
+       tmp_out = os_malloc(skip + out_len);
+       if (!tmp_out)
+               return -1;
+       _out = tmp_out;
 
        rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
        if (!rnd) {
@@ -3205,29 +3213,22 @@ static int openssl_tls_prf(struct tls_connection *conn,
        master_key_len = SSL_SESSION_get_master_key(sess, master_key,
                                                    sizeof(master_key));
 
-       if (server_random_first) {
-               os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE);
-               os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random,
-                         SSL3_RANDOM_SIZE);
-       } else {
-               os_memcpy(rnd, client_random, SSL3_RANDOM_SIZE);
-               os_memcpy(rnd + SSL3_RANDOM_SIZE, server_random,
-                         SSL3_RANDOM_SIZE);
-       }
+       os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE);
+       os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random, SSL3_RANDOM_SIZE);
 
        if (os_strcmp(ver, "TLSv1.2") == 0) {
                tls_prf_sha256(master_key, master_key_len,
-                              label, rnd, 2 * SSL3_RANDOM_SIZE,
+                              "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
                               _out, skip + out_len);
                ret = 0;
        } else if (tls_prf_sha1_md5(master_key, master_key_len,
-                                   label, rnd, 2 * SSL3_RANDOM_SIZE,
+                                   "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
                                    _out, skip + out_len) == 0) {
                ret = 0;
        }
        os_memset(master_key, 0, sizeof(master_key));
        os_free(rnd);
-       if (ret == 0 && skip_keyblock)
+       if (ret == 0)
                os_memcpy(out, _out + skip, out_len);
        bin_clear_free(tmp_out, skip);
 
@@ -3236,26 +3237,6 @@ static int openssl_tls_prf(struct tls_connection *conn,
 }
 
 
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
-                      const char *label, int server_random_first,
-                      int skip_keyblock, u8 *out, size_t out_len)
-{
-       if (conn == NULL)
-               return -1;
-       if (server_random_first || skip_keyblock)
-               return openssl_tls_prf(conn, label,
-                                      server_random_first, skip_keyblock,
-                                      out, out_len);
-       if (SSL_export_keying_material(conn->ssl, out, out_len, label,
-                                      os_strlen(label), NULL, 0, 0) == 1) {
-               wpa_printf(MSG_DEBUG, "OpenSSL: Using internal PRF");
-               return 0;
-       }
-       return openssl_tls_prf(conn, label, server_random_first,
-                              skip_keyblock, out, out_len);
-}
-
-
 static struct wpabuf *
 openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data,
                  int server)
index e8587fdaac03a6039608d6629cbb2ee9a9d97906..9ef671c41c7d7878b38cfc5b5bfeaeffa34276b1 100644 (file)
@@ -93,8 +93,7 @@ void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random,
 }
 
 
-u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
-                        const char *label, size_t len)
+u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn, size_t len)
 {
        u8 *out;
 
@@ -102,7 +101,7 @@ u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
        if (out == NULL)
                return NULL;
 
-       if (tls_connection_prf(ssl_ctx, conn, label, 1, 1, out, len)) {
+       if (tls_connection_get_eap_fast_key(ssl_ctx, conn, out, len)) {
                os_free(out);
                return NULL;
        }
index 6756dd23fc8f4c042b8e83ba064331d8407a24fa..724204cb5e3252132eeb0bfb2327d13a00098720 100644 (file)
@@ -98,7 +98,7 @@ struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf);
 void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random,
                                   const u8 *client_random, u8 *master_secret);
 u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
-                        const char *label, size_t len);
+                        size_t len);
 int eap_fast_derive_eap_msk(const u8 *simck, u8 *msk);
 int eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk);
 int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
index 7d954182ca009bd0ac9b878d9abdd72f8f103a75..964ebe74fede8003aeba4575a5531fbb2a9d841b 100644 (file)
@@ -275,7 +275,7 @@ static int eap_fast_derive_key_auth(struct eap_sm *sm,
         * Extra key material after TLS key_block: session_key_seed[40]
         */
 
-       sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, "key expansion",
+       sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
                                  EAP_FAST_SKS_LEN);
        if (sks == NULL) {
                wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
@@ -303,7 +303,6 @@ static int eap_fast_derive_key_provisioning(struct eap_sm *sm,
        os_free(data->key_block_p);
        data->key_block_p = (struct eap_fast_key_block_provisioning *)
                eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
-                                   "key expansion",
                                    sizeof(*data->key_block_p));
        if (data->key_block_p == NULL) {
                wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
index 406c1624de36a098097db274baebaad98838d84a..0dcb9c138f81de21522f317a2622659f60c9717d 100644 (file)
@@ -328,8 +328,8 @@ u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
        if (out == NULL)
                return NULL;
 
-       if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, 0,
-                              out, len)) {
+       if (tls_connection_export_key(data->ssl_ctx, data->conn, label, out,
+                                     len)) {
                os_free(out);
                return NULL;
        }
index 6993159788d3a8c415ffebd0d68118e6323c6bbc..20491726880e925f33b82a70157cbe0bfba8b6eb 100644 (file)
@@ -278,7 +278,7 @@ static void eap_fast_derive_key_auth(struct eap_sm *sm,
         * Extra key material after TLS key_block: session_key_seed[40]
         */
 
-       sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, "key expansion",
+       sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
                                  EAP_FAST_SKS_LEN);
        if (sks == NULL) {
                wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
@@ -305,7 +305,6 @@ static void eap_fast_derive_key_provisioning(struct eap_sm *sm,
        os_free(data->key_block_p);
        data->key_block_p = (struct eap_fast_key_block_provisioning *)
                eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
-                                   "key expansion",
                                    sizeof(*data->key_block_p));
        if (data->key_block_p == NULL) {
                wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
index 05677b70e88738d85ee62c78e8352585dd00f920..69096954b8262668919c2cbc393ceb33d6f62cb6 100644 (file)
@@ -115,8 +115,8 @@ u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
        if (out == NULL)
                return NULL;
 
-       if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, 0,
-                              out, len)) {
+       if (tls_connection_export_key(sm->ssl_ctx, data->conn, label, out,
+                                     len)) {
                os_free(out);
                return NULL;
        }