chbind.c
ifneq (${OPENSSL_LIBS},)
-SOURCES += tls.c mppe_keys.c
+SOURCES += tls.c crypto.c
endif
TGT_PREREQS := libfreeradius-radius.a libfreeradius-util.a
--- /dev/null
+/*
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file lib/eap/mppe_keys.c
+ * @brief MPPE key calculation API
+ *
+ * @author Henrik Eriksson <henriken@axis.com>
+ * @author Lars Viklund <larsv@axis.com>
+ *
+ * @copyright 2002 Axis Communications AB
+ * @copyright 2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
+
+#define __STDC_WANT_LIB_EXT1__ 1
+#include <string.h>
+
+#include <openssl/hmac.h>
+
+#include <freeradius-devel/util/sha1.h>
+#include <freeradius-devel/tls/base.h>
+
+#include "tls.h"
+#include "base.h"
+#include "attrs.h"
+
+static void crypto_rfc4346_p_hash(uint8_t *out, size_t out_len,
+ EVP_MD const *evp_md,
+ uint8_t const *secret, size_t secret_len,
+ uint8_t const *seed, size_t seed_len)
+{
+ HMAC_CTX *ctx_a, *ctx_out;
+ uint8_t a[HMAC_MAX_MD_CBLOCK];
+ size_t size;
+
+ ctx_a = HMAC_CTX_new();
+ ctx_out = HMAC_CTX_new();
+#ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
+ HMAC_CTX_set_flags(ctx_a, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+ HMAC_CTX_set_flags(ctx_out, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+#endif
+ HMAC_Init_ex(ctx_a, secret, secret_len, evp_md, NULL);
+ HMAC_Init_ex(ctx_out, secret, secret_len, evp_md, NULL);
+
+ size = HMAC_size(ctx_out);
+
+ /* Calculate A(1) */
+ HMAC_Update(ctx_a, seed, seed_len);
+ HMAC_Final(ctx_a, a, NULL);
+
+ while (1) {
+ /* Calculate next part of output */
+ HMAC_Update(ctx_out, a, size);
+ HMAC_Update(ctx_out, seed, seed_len);
+
+ /* Check if last part */
+ if (out_len < size) {
+ HMAC_Final(ctx_out, a, NULL);
+ memcpy(out, a, out_len);
+ break;
+ }
+
+ /* Place digest in output buffer */
+ HMAC_Final(ctx_out, out, NULL);
+ HMAC_Init_ex(ctx_out, NULL, 0, NULL, NULL);
+ out += size;
+ out_len -= size;
+
+ /* Calculate next A(i) */
+ HMAC_Init_ex(ctx_a, NULL, 0, NULL, NULL);
+ HMAC_Update(ctx_a, a, size);
+ HMAC_Final(ctx_a, a, NULL);
+ }
+
+ HMAC_CTX_free(ctx_a);
+ HMAC_CTX_free(ctx_out);
+#ifdef __STDC_LIB_EXT1__
+ memset_s(a, 0, sizeof(a), sizeof(a));
+#else
+ memset(a, 0, sizeof(a));
+#endif
+}
+
+
+void eap_crypto_rfc4346_prf(uint8_t *out, size_t out_len, uint8_t *scratch,
+ uint8_t const *secret, size_t secret_len,
+ uint8_t const *seed, size_t seed_len)
+{
+ unsigned int i;
+ unsigned int len = (secret_len + 1) / 2;
+ uint8_t const *s1 = secret;
+ uint8_t const *s2 = secret + (secret_len - len);
+
+ crypto_rfc4346_p_hash(out, out_len, EVP_md5(), s1, len, seed, seed_len);
+ crypto_rfc4346_p_hash(scratch, out_len, EVP_sha1(), s2, len, seed, seed_len);
+
+ for (i = 0; i < out_len; i++) out[i] ^= scratch[i];
+}
+
+#define EAP_TLS_MPPE_KEY_LEN 32
+
+/** Generate keys according to RFC 2716 and add to the reply
+ *
+ */
+void eap_crypto_mppe_keys(REQUEST *request, SSL *ssl, char const *prf_label, size_t prf_label_len)
+{
+ uint8_t out[4 * EAP_TLS_MPPE_KEY_LEN];
+ uint8_t *p;
+ size_t seed_len = prf_label_len;
+ size_t master_key_len;
+ uint8_t seed[64 + (2 * SSL3_RANDOM_SIZE)];
+ uint8_t scratch[sizeof(out)];
+ uint8_t master_key[SSL_MAX_MASTER_KEY_LENGTH];
+
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+ if (SSL_export_keying_material(ssl, out, sizeof(out), prf_label, prf_label_len, NULL, 0, 0) != 1) /* Fallback */
+#endif
+
+ {
+ p = seed;
+ memcpy(p, prf_label, seed_len);
+ p += seed_len;
+
+ (void) SSL_get_client_random(ssl, p, SSL3_RANDOM_SIZE);
+ p += SSL3_RANDOM_SIZE;
+ seed_len += SSL3_RANDOM_SIZE;
+
+ (void) SSL_get_server_random(ssl, p, SSL3_RANDOM_SIZE);
+ seed_len += SSL3_RANDOM_SIZE;
+
+ master_key_len = SSL_SESSION_get_master_key(SSL_get_session(ssl), master_key, sizeof(master_key));
+ eap_crypto_rfc4346_prf(out, sizeof(out), scratch, master_key, master_key_len, seed, seed_len);
+ }
+
+ RDEBUG2("Adding session keys");
+ p = out;
+ eap_add_reply(request, attr_ms_mppe_recv_key, p, EAP_TLS_MPPE_KEY_LEN);
+ p += EAP_TLS_MPPE_KEY_LEN;
+ eap_add_reply(request, attr_ms_mppe_send_key, p, EAP_TLS_MPPE_KEY_LEN);
+
+ eap_add_reply(request, attr_eap_msk, out, 64);
+ eap_add_reply(request, attr_eap_emsk, out + 64, 64);
+}
+
+
+/*
+ * Generate the challenge using a PRF label.
+ *
+ * It's in the TLS module simply because it's only a few lines
+ * of code, and it needs access to the TLS PRF functions.
+ */
+void eap_crypto_challenge(SSL *s, uint8_t *buffer, uint8_t *scratch, size_t size, char const *prf_label)
+{
+ uint8_t *p;
+ size_t len, master_key_len;
+ uint8_t master_key[SSL_MAX_MASTER_KEY_LENGTH];
+ uint8_t seed[128 + (2 * SSL3_RANDOM_SIZE)];
+
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+ if (SSL_export_keying_material(s, buffer, size, prf_label,
+ strlen(prf_label), NULL, 0, 0) == 1) return;
+
+#endif
+
+ len = strlen(prf_label);
+ if (len > 128) len = 128;
+
+ p = seed;
+ memcpy(p, prf_label, len);
+ p += len;
+
+ (void) SSL_get_client_random(s, p, SSL3_RANDOM_SIZE);
+ p += SSL3_RANDOM_SIZE;
+ (void) SSL_get_server_random(s, p, SSL3_RANDOM_SIZE);
+ p += SSL3_RANDOM_SIZE;
+
+ master_key_len = SSL_SESSION_get_master_key(SSL_get_session(s), master_key, sizeof(master_key));
+ eap_crypto_rfc4346_prf(buffer, size, scratch, master_key, master_key_len, seed, p - seed);
+}
+
+int eap_crypto_tls_session_id(TALLOC_CTX *ctx, uint8_t **out,
+ SSL *ssl, uint8_t eap_type,
+ char const *prf_label, size_t prf_len)
+{
+ uint8_t *buff = NULL, *p;
+
+ *out = NULL;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ if (!prf_label) goto random_based_session_id;
+
+ switch (SSL_SESSION_get_protocol_version(SSL_get_session(ssl))) {
+ case SSL2_VERSION: /* Should never happen */
+ case SSL3_VERSION: /* Should never happen */
+ return - 1;
+
+ case TLS1_VERSION: /* No Method ID */
+ case TLS1_1_VERSION: /* No Method ID */
+ case TLS1_2_VERSION: /* No Method ID */
+#endif
+ random_based_session_id:
+ MEM(buff = p = talloc_array(ctx, uint8_t, sizeof(eap_type) + (2 * SSL3_RANDOM_SIZE)));
+ *p++ = eap_type;
+
+ SSL_get_client_random(ssl, p, SSL3_RANDOM_SIZE);
+ p += SSL3_RANDOM_SIZE;
+ SSL_get_server_random(ssl, p, SSL3_RANDOM_SIZE);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ break;
+
+ /*
+ * Session-Id = <EAP-Type> || Method-Id
+ * Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id", "", 64)
+ */
+ case TLS1_3_VERSION:
+ default:
+ {
+ MEM(buff = p = talloc_array(ctx, uint8_t, sizeof(eap_type) + 64));
+ *p++ = eap_type;
+ SSL_export_keying_material(ssl, p, 64, prf_label, prf_len, NULL, 0, 0);
+ }
+ break;
+ }
+#endif
+ *out = buff;
+
+ return 0;
+}
+++ /dev/null
-/*
- * This program is is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/**
- * $Id$
- * @file lib/eap/mppe_keys.c
- * @brief MPPE key calculation API
- *
- * @author Henrik Eriksson <henriken@axis.com>
- * @author Lars Viklund <larsv@axis.com>
- *
- * @copyright 2002 Axis Communications AB
- * @copyright 2006 The FreeRADIUS server project
- */
-
-RCSID("$Id$")
-USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
-
-#define __STDC_WANT_LIB_EXT1__ 1
-#include <string.h>
-
-#include <openssl/hmac.h>
-
-#include <freeradius-devel/util/sha1.h>
-
-#include "tls.h"
-#include "base.h"
-#include "attrs.h"
-
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
-/*
- * OpenSSL compatibility, to avoid ifdef's through the rest of the code.
- */
-size_t SSL_get_client_random(const SSL *s, unsigned char *out, size_t outlen)
-{
- if (!outlen) return sizeof(s->s3->client_random);
-
- if (outlen > sizeof(s->s3->client_random)) outlen = sizeof(s->s3->client_random);
-
- memcpy(out, s->s3->client_random, outlen);
- return outlen;
-}
-
-size_t SSL_get_server_random(const SSL *s, unsigned char *out, size_t outlen)
-{
- if (!outlen) return sizeof(s->s3->server_random);
-
- if (outlen > sizeof(s->s3->server_random)) outlen = sizeof(s->s3->server_random);
-
- memcpy(out, s->s3->server_random, outlen);
- return outlen;
-}
-
-static size_t SSL_SESSION_get_master_key(const SSL_SESSION *s, unsigned char *out, size_t outlen)
-{
- if (!outlen) return s->master_key_length;
-
- if (outlen > (size_t)s->master_key_length) outlen = (size_t)s->master_key_length;
-
- memcpy(out, s->master_key, outlen);
- return outlen;
-}
-#endif
-
-/*
- * TLS PRF from RFC 2246
- */
-static void P_hash(EVP_MD const *evp_md,
- unsigned char const *secret, unsigned int secret_len,
- unsigned char const *seed, unsigned int seed_len,
- unsigned char *out, unsigned int out_len)
-{
- HMAC_CTX *ctx_a, *ctx_out;
- unsigned char a[HMAC_MAX_MD_CBLOCK];
- unsigned int size;
-
- ctx_a = HMAC_CTX_new();
- ctx_out = HMAC_CTX_new();
-#ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
- HMAC_CTX_set_flags(ctx_a, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
- HMAC_CTX_set_flags(ctx_out, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
-#endif
- HMAC_Init_ex(ctx_a, secret, secret_len, evp_md, NULL);
- HMAC_Init_ex(ctx_out, secret, secret_len, evp_md, NULL);
-
- size = HMAC_size(ctx_out);
-
- /* Calculate A(1) */
- HMAC_Update(ctx_a, seed, seed_len);
- HMAC_Final(ctx_a, a, NULL);
-
- while (1) {
- /* Calculate next part of output */
- HMAC_Update(ctx_out, a, size);
- HMAC_Update(ctx_out, seed, seed_len);
-
- /* Check if last part */
- if (out_len < size) {
- HMAC_Final(ctx_out, a, NULL);
- memcpy(out, a, out_len);
- break;
- }
-
- /* Place digest in output buffer */
- HMAC_Final(ctx_out, out, NULL);
- HMAC_Init_ex(ctx_out, NULL, 0, NULL, NULL);
- out += size;
- out_len -= size;
-
- /* Calculate next A(i) */
- HMAC_Init_ex(ctx_a, NULL, 0, NULL, NULL);
- HMAC_Update(ctx_a, a, size);
- HMAC_Final(ctx_a, a, NULL);
- }
-
- HMAC_CTX_free(ctx_a);
- HMAC_CTX_free(ctx_out);
-#ifdef __STDC_LIB_EXT1__
- memset_s(a, 0, sizeof(a), sizeof(a));
-#else
- memset(a, 0, sizeof(a));
-#endif
-}
-
-/* EAP-FAST Pseudo-Random Function (T-PRF): RFC 4851, Section 5.5 */
-void T_PRF(unsigned char const *secret, unsigned int secret_len,
- char const *prf_label,
- unsigned char const *seed, unsigned int seed_len,
- unsigned char *out, unsigned int out_len)
-{
- size_t prf_size = strlen(prf_label);
- size_t pos;
- uint8_t *buf;
-
- if (prf_size > 128) prf_size = 128;
- prf_size++; /* include trailing zero */
-
- buf = talloc_size(NULL, SHA1_DIGEST_LENGTH + prf_size + seed_len + 2 + 1);
-
- memcpy(buf + SHA1_DIGEST_LENGTH, prf_label, prf_size);
- if (seed) memcpy(buf + SHA1_DIGEST_LENGTH + prf_size, seed, seed_len);
- *(uint16_t *)&buf[SHA1_DIGEST_LENGTH + prf_size + seed_len] = htons(out_len);
- buf[SHA1_DIGEST_LENGTH + prf_size + seed_len + 2] = 1;
-
- // T1 is just the seed
- fr_hmac_sha1(buf, buf + SHA1_DIGEST_LENGTH, prf_size + seed_len + 2 + 1, secret, secret_len);
-
-#define MIN(a,b) (((a)>(b)) ? (b) : (a))
- memcpy(out, buf, MIN(out_len, SHA1_DIGEST_LENGTH));
-
- pos = SHA1_DIGEST_LENGTH;
- while (pos < out_len) {
- buf[SHA1_DIGEST_LENGTH + prf_size + seed_len + 2]++;
-
- fr_hmac_sha1(buf, buf, SHA1_DIGEST_LENGTH + prf_size + seed_len + 2 + 1, secret, secret_len);
- memcpy(&out[pos], buf, MIN(out_len - pos, SHA1_DIGEST_LENGTH));
-
- if (out_len - pos <= SHA1_DIGEST_LENGTH)
- break;
-
- pos += SHA1_DIGEST_LENGTH;
- }
-
- memset(buf, 0, SHA1_DIGEST_LENGTH + prf_size + seed_len + 2 + 1);
- talloc_free(buf);
-}
-
-static void PRF(unsigned char const *secret, unsigned int secret_len,
- unsigned char const *seed, unsigned int seed_len,
- unsigned char *out, unsigned char *buf, unsigned int out_len)
-{
- unsigned int i;
- unsigned int len = (secret_len + 1) / 2;
- uint8_t const *s1 = secret;
- uint8_t const *s2 = secret + (secret_len - len);
-
- P_hash(EVP_md5(), s1, len, seed, seed_len, out, out_len);
- P_hash(EVP_sha1(), s2, len, seed, seed_len, buf, out_len);
-
- for (i=0; i < out_len; i++) {
- out[i] ^= buf[i];
- }
-}
-
-#define EAP_TLS_MPPE_KEY_LEN 32
-
-/** Generate keys according to RFC 2716 and add to the reply
- *
- */
-void eap_tls_gen_mppe_keys(REQUEST *request, SSL *s, char const *prf_label)
-{
- uint8_t out[4 * EAP_TLS_MPPE_KEY_LEN];
- uint8_t *p;
- size_t prf_size;
- size_t master_key_len;
- uint8_t seed[64 + (2 * SSL3_RANDOM_SIZE)];
- uint8_t buf[4 * EAP_TLS_MPPE_KEY_LEN];
- uint8_t master_key[SSL_MAX_MASTER_KEY_LENGTH];
-
- prf_size = strlen(prf_label);
-
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
- if (SSL_export_keying_material(s, out, sizeof(out), prf_label, prf_size, NULL, 0, 0) != 1) /* Fallback */
-#endif
-
- {
- p = seed;
- memcpy(p, prf_label, prf_size);
- p += prf_size;
-
- (void) SSL_get_client_random(s, p, SSL3_RANDOM_SIZE);
- p += SSL3_RANDOM_SIZE;
- prf_size += SSL3_RANDOM_SIZE;
-
- (void) SSL_get_server_random(s, p, SSL3_RANDOM_SIZE);
- prf_size += SSL3_RANDOM_SIZE;
-
- master_key_len = SSL_SESSION_get_master_key(SSL_get_session(s), master_key, sizeof(master_key));
- PRF(master_key, master_key_len, seed, prf_size, out, buf, sizeof(out));
- }
-
- RDEBUG2("Adding session keys");
- p = out;
- eap_add_reply(request, attr_ms_mppe_recv_key, p, EAP_TLS_MPPE_KEY_LEN);
- p += EAP_TLS_MPPE_KEY_LEN;
- eap_add_reply(request, attr_ms_mppe_send_key, p, EAP_TLS_MPPE_KEY_LEN);
-
- eap_add_reply(request, attr_eap_msk, out, 64);
- eap_add_reply(request, attr_eap_emsk, out + 64, 64);
-}
-
-
-/*
- * Generate the challenge using a PRF label.
- *
- * It's in the TLS module simply because it's only a few lines
- * of code, and it needs access to the TLS PRF functions.
- */
-void eap_tls_gen_challenge(SSL *s, uint8_t *buffer, uint8_t *scratch, size_t size, char const *prf_label)
-{
- uint8_t *p;
- size_t len, master_key_len;
- uint8_t master_key[SSL_MAX_MASTER_KEY_LENGTH];
- uint8_t seed[128 + 2*SSL3_RANDOM_SIZE];
-
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
- if (SSL_export_keying_material(s, buffer, size, prf_label,
- strlen(prf_label), NULL, 0, 0) == 1) return;
-
-#endif
-
- len = strlen(prf_label);
- if (len > 128) len = 128;
-
- p = seed;
- memcpy(p, prf_label, len);
- p += len;
-
- (void) SSL_get_client_random(s, p, SSL3_RANDOM_SIZE);
- p += SSL3_RANDOM_SIZE;
- (void) SSL_get_server_random(s, p, SSL3_RANDOM_SIZE);
- p += SSL3_RANDOM_SIZE;
-
- master_key_len = SSL_SESSION_get_master_key(SSL_get_session(s), master_key, sizeof(master_key));
- PRF(master_key, master_key_len, seed, p - seed, buffer, scratch, size);
-}
-
-
-/*
- * Same as before, but for EAP-FAST the order of {server,client}_random is flipped
- */
-void eap_fast_tls_gen_challenge(SSL *s, uint8_t *buffer, uint8_t *scratch, size_t size, char const *prf_label)
-{
- uint8_t *p;
- size_t len, master_key_len;
- uint8_t seed[128 + 2*SSL3_RANDOM_SIZE];
- uint8_t master_key[SSL_MAX_MASTER_KEY_LENGTH];
-
- len = strlen(prf_label);
- if (len > 128) len = 128;
-
- p = seed;
- memcpy(p, prf_label, len);
- p += len;
- (void) SSL_get_server_random(s, p, SSL3_RANDOM_SIZE);
- p += SSL3_RANDOM_SIZE;
- (void) SSL_get_client_random(s, p, SSL3_RANDOM_SIZE);
- p += SSL3_RANDOM_SIZE;
-
- master_key_len = SSL_SESSION_get_master_key(SSL_get_session(s), master_key, sizeof(master_key));
- PRF(master_key, master_key_len, seed, p - seed, buffer, scratch, size);
-}
-
-/*
- * Actually generates EAP-Session-Id, which is an internal server
- * attribute. Not all systems want to send EAP-Key-Name
- */
-void eap_tls_gen_session_id(RADIUS_PACKET *packet, SSL *ssl, uint8_t eap_type)
-{
- VALUE_PAIR *vp;
- uint8_t *buff = NULL, *p;
-
- vp = fr_pair_afrom_da(packet, attr_eap_session_id);
- if (!vp) return;
-
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
- if (eap_type != FR_EAP_TLS) goto random_based_session_id;
-
- switch (SSL_SESSION_get_protocol_version(SSL_get_session(ssl))) {
- case SSL2_VERSION: /* Should never happen */
- case SSL3_VERSION: /* Should never happen */
- return;
-
- case TLS1_VERSION: /* No Method ID */
- case TLS1_1_VERSION: /* No Method ID */
- case TLS1_2_VERSION: /* No Method ID */
-#endif
- random_based_session_id:
- MEM(buff = p = talloc_array(vp, uint8_t, sizeof(eap_type) + SSL3_RANDOM_SIZE + SSL3_RANDOM_SIZE));
- *p++ = eap_type;
-
- SSL_get_client_random(ssl, p, SSL3_RANDOM_SIZE);
- p += SSL3_RANDOM_SIZE;
- SSL_get_server_random(ssl, p, SSL3_RANDOM_SIZE);
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
- break;
-
- /*
- * Session-Id = <EAP-Type> || Method-Id
- * Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id", "", 64)
- */
- case TLS1_3_VERSION:
- default:
- {
- char const prf_label[] = "EXPORTER_EAP_TLS_Method-Id";
-
- MEM(buff = p = talloc_array(vp, uint8_t, sizeof(eap_type) + 64));
- *p++ = eap_type;
- SSL_export_keying_material(ssl, p, 64, prf_label, sizeof(prf_label) - 1, NULL, 0, 0);
- }
- break;
- }
-#endif
-
- fr_pair_value_memsteal(vp, buff);
- fr_pair_add(&packet->vps, vp);
-}
* We add the MPPE keys here. These are used by the NAS. The supplicant
* will derive the same keys separately.
*
- * @param eap_session that completed successfully.
+ * @param[in] eap_session that completed successfully.
+ * @param[in] keying_prf_label PRF label to use for generating keying material.
+ * If NULL, no MPPE keys will be generated.
+ * @param[in] keying_prf_label_len Length of the keying PRF label.
+ * @param[in] sessid_prf_label PRF label to use when generating the session ID.
+ * If NULL, session ID will be based on client/server randoms.
+ * @param[in] sessid_prf_label_len Length of the session ID PRF label.
* @return
* - 0 on success.
* - -1 on failure.
*/
-int eap_tls_success(eap_session_t *eap_session, char const *prf_label)
+int eap_tls_success(eap_session_t *eap_session,
+ char const *keying_prf_label, size_t keying_prf_label_len,
+ char const *sessid_prf_label, size_t sessid_prf_label_len)
{
REQUEST *request = eap_session->request;
eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
/*
* Automatically generate MPPE keying material.
*/
- if (prf_label) eap_tls_gen_mppe_keys(eap_session->request, tls_session->ssl, prf_label);
+ if (keying_prf_label) eap_crypto_mppe_keys(eap_session->request, tls_session->ssl,
+ keying_prf_label, keying_prf_label_len);
- eap_tls_gen_session_id(eap_session->request->reply, tls_session->ssl, eap_session->type);
+ /*
+ * Add the TLS session ID to the request
+ */
+ {
+ uint8_t *session_id;
+ VALUE_PAIR *vp;
+
+ if (eap_crypto_tls_session_id(eap_session->request->reply, &session_id,
+ tls_session->ssl, eap_session->type,
+ sessid_prf_label, sessid_prf_label_len) < 0) return -1;
+
+ MEM(pair_add_reply(&vp, attr_eap_session_id) >= 0);
+ fr_pair_value_memsteal(vp, session_id);
+
+ RINDENT();
+ RDEBUG2("&reply:%pP", vp);
+ REXDENT();
+ }
return 0;
}
* Init is finished. The rest is
* application data.
*/
- tls_session->info.content_type = application_data;
+ tls_session->info.content_type = SSL3_RT_APPLICATION_DATA;
return EAP_TLS_ESTABLISHED;
}
int eap_tls_start(eap_session_t *eap_session) CC_HINT(nonnull);
-int eap_tls_success(eap_session_t *eap_session, char const *prf_label) CC_HINT(nonnull(1));
+int eap_tls_success(eap_session_t *eap_session,
+ char const *keying_prf_label, size_t keying_prf_label_len,
+ char const *sessid_prf_label, size_t sessid_prf_label_len) CC_HINT(nonnull(1));
int eap_tls_fail(eap_session_t *eap_session) CC_HINT(nonnull);
tls_record_t *record, size_t record_len, size_t frag_len);
/* MPPE key generation */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
-size_t SSL_get_client_random(const SSL *ssl, unsigned char *out, size_t outlen);
-size_t SSL_get_server_random(const SSL *ssl, unsigned char *out, size_t outlen);
-#endif
-void T_PRF(unsigned char const *secret, unsigned int secret_len, char const *prf_label, unsigned char const *seed, unsigned int seed_len, unsigned char *out, unsigned int out_len) CC_HINT(nonnull(1,3,6));
+void eap_crypto_rfc4346_prf(uint8_t *out, size_t out_len, uint8_t *scratch,
+ uint8_t const *secret, size_t secret_len,
+ uint8_t const *seed, size_t seed_len);
-void eap_tls_gen_mppe_keys(REQUEST *request, SSL *s, char const *prf_label) CC_HINT(nonnull);
+void eap_crypto_mppe_keys(REQUEST *request, SSL *ssl,
+ char const *prf_label, size_t prf_label_len) CC_HINT(nonnull);
-void eap_tls_gen_challenge(SSL *ssl, uint8_t *buffer, uint8_t *scratch, size_t size, char const *prf_label) CC_HINT(nonnull);
-void eap_fast_tls_gen_challenge(SSL *ssl, uint8_t *buffer, uint8_t *scratch, size_t size, char const *prf_label) CC_HINT(nonnull);
+void eap_crypto_challenge(SSL *ssl, uint8_t *buffer, uint8_t *scratch, size_t size, char const *prf_label) CC_HINT(nonnull);
-void eap_tls_gen_session_id(RADIUS_PACKET *packet, SSL *s, uint8_t type) CC_HINT(nonnull);
+int eap_crypto_tls_session_id(TALLOC_CTX *ctx, uint8_t **out,
+ SSL *ssl, uint8_t eap_type,
+ char const *prf_label, size_t prf_len);
/* EAP-TLS framework */
eap_tls_session_t *eap_tls_session_init(eap_session_t *eap_session, fr_tls_conf_t *tls_conf, bool client_cert) CC_HINT(nonnull);
typedef struct fr_tls_conf_t fr_tls_conf_t;
-/*
- * Following enums from rfc2246
- *
- * Hmm... since we dpeend on OpenSSL, it would be smarter to
- * use the OpenSSL names for these.
- */
-enum ContentType {
- change_cipher_spec = 20,
- alert = 21,
- handshake = 22,
- application_data = 23
-};
-
-enum AlertLevel {
- warning = 1,
- fatal = 2
-};
-
-enum AlertDescription {
- close_notify = 0,
- unexpected_message = 10,
- bad_record_mac = 20,
- decryption_failed = 21,
- record_overflow = 22,
- decompression_failure = 30,
- handshake_failure = 40,
- bad_certificate = 42,
- unsupported_certificate = 43,
- certificate_revoked = 44,
- certificate_expired = 45,
- certificate_unknown = 46,
- illegal_parameter = 47,
- unknown_ca = 48,
- access_denied = 49,
- decode_error = 50,
- decrypt_error = 51,
- export_restriction = 60,
- protocol_version = 70,
- insufficient_security = 71,
- internal_error = 80,
- user_canceled = 90,
- no_renegotiation = 100
-};
-
-enum HandshakeType {
- hello_request = 0,
- client_hello = 1,
- server_hello = 2,
- certificate = 11,
- server_key_exchange = 12,
- certificate_request = 13,
- server_hello_done = 14,
- certificate_verify = 15,
- client_key_exchange = 16,
- handshake_finished = 20
-};
-
extern int fr_tls_ex_index_vps;
extern int fr_tls_max_threads;
SRC_INCDIRS := ${top_srcdir}/src/modules/rlm_eap/ ${top_srcdir}/src/modules/rlm_eap/lib/base/
-TGT_PREREQS := libfreeradius-radius.a libfreeradius-util.a libfreeradius-eap.a
+TGT_PREREQS := libfreeradius-radius.a libfreeradius-util.a libfreeradius-tls.a libfreeradius-eap.a
}
/*
- * eap_tls_gen_mppe_keys() is unsuitable for EAP-FAST as Cisco decided
+ * eap_crypto_mppe_keys() is unsuitable for EAP-FAST as Cisco decided
* it would be a great idea to flip the recv/send keys around
*/
#define EAPTLS_MPPE_KEY_LEN 32
#include <stdio.h>
#include <freeradius-devel/util/base.h>
+#include <freeradius-devel/tls/base.h>
+#include <freeradius-devel/eap/tls.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#include "eap_fast_crypto.h"
+/* EAP-FAST Pseudo-Random Function (T-PRF): RFC 4851, Section 5.5 */
+void T_PRF(unsigned char const *secret, unsigned int secret_len,
+ char const *prf_label,
+ unsigned char const *seed, unsigned int seed_len,
+ unsigned char *out, unsigned int out_len)
+{
+ size_t prf_size = strlen(prf_label);
+ size_t pos;
+ uint8_t *buf;
+
+ if (prf_size > 128) prf_size = 128;
+ prf_size++; /* include trailing zero */
+
+ buf = talloc_size(NULL, SHA1_DIGEST_LENGTH + prf_size + seed_len + 2 + 1);
+
+ memcpy(buf + SHA1_DIGEST_LENGTH, prf_label, prf_size);
+ if (seed) memcpy(buf + SHA1_DIGEST_LENGTH + prf_size, seed, seed_len);
+ *(uint16_t *)&buf[SHA1_DIGEST_LENGTH + prf_size + seed_len] = htons(out_len);
+ buf[SHA1_DIGEST_LENGTH + prf_size + seed_len + 2] = 1;
+
+ // T1 is just the seed
+ fr_hmac_sha1(buf, buf + SHA1_DIGEST_LENGTH, prf_size + seed_len + 2 + 1, secret, secret_len);
+
+#define MIN(a,b) (((a)>(b)) ? (b) : (a))
+ memcpy(out, buf, MIN(out_len, SHA1_DIGEST_LENGTH));
+
+ pos = SHA1_DIGEST_LENGTH;
+ while (pos < out_len) {
+ buf[SHA1_DIGEST_LENGTH + prf_size + seed_len + 2]++;
+
+ fr_hmac_sha1(buf, buf, SHA1_DIGEST_LENGTH + prf_size + seed_len + 2 + 1, secret, secret_len);
+ memcpy(&out[pos], buf, MIN(out_len - pos, SHA1_DIGEST_LENGTH));
+
+ if (out_len - pos <= SHA1_DIGEST_LENGTH)
+ break;
+
+ pos += SHA1_DIGEST_LENGTH;
+ }
+
+ memset(buf, 0, SHA1_DIGEST_LENGTH + prf_size + seed_len + 2 + 1);
+ talloc_free(buf);
+}
+
// http://stackoverflow.com/a/29838852
static void NEVER_RETURNS handleErrors(void)
{
return -1;
}
}
+
+/*
+ * Same as before, but for EAP-FAST the order of {server,client}_random is flipped
+ */
+void eap_fast_tls_gen_challenge(SSL *s, uint8_t *buffer, uint8_t *scratch, size_t size, char const *prf_label)
+{
+ uint8_t *p;
+ size_t len, master_key_len;
+ uint8_t seed[128 + (2 * SSL3_RANDOM_SIZE)];
+ uint8_t master_key[SSL_MAX_MASTER_KEY_LENGTH];
+
+ len = strlen(prf_label);
+ if (len > 128) len = 128;
+
+ p = seed;
+ memcpy(p, prf_label, len);
+ p += len;
+ (void) SSL_get_server_random(s, p, SSL3_RANDOM_SIZE);
+ p += SSL3_RANDOM_SIZE;
+ (void) SSL_get_client_random(s, p, SSL3_RANDOM_SIZE);
+ p += SSL3_RANDOM_SIZE;
+
+ master_key_len = SSL_SESSION_get_master_key(SSL_get_session(s), master_key, sizeof(master_key));
+ eap_crypto_rfc4346_prf(buffer, size, scratch, master_key, master_key_len, seed, p - seed);
+}
*/
RCSIDH(eap_fast_crypto_h, "$Id$")
+void T_PRF(unsigned char const *secret, unsigned int secret_len, char const *prf_label, unsigned char const *seed, unsigned int seed_len, unsigned char *out, unsigned int out_len) CC_HINT(nonnull(1,3,6));
+
int eap_fast_encrypt(uint8_t const *plaintext, size_t plaintext_len,
uint8_t const *aad, size_t aad_len,
uint8_t const *key, uint8_t *iv, unsigned char *ciphertext,
int eap_fast_decrypt(uint8_t const *ciphertext, size_t ciphertext_len,
uint8_t const *aad, size_t aad_len,
uint8_t const *tag, uint8_t const *key, uint8_t const *iv, uint8_t *plaintext);
+
+void eap_fast_tls_gen_challenge(SSL *ssl, uint8_t *buffer, uint8_t *scratch, size_t size, char const *prf_label) CC_HINT(nonnull);
* Success: Automatically return MPPE keys.
*/
case FR_CODE_ACCESS_ACCEPT:
- if (eap_tls_success(eap_session, NULL) < 0) return RLM_MODULE_FAIL;
+ if (eap_tls_success(eap_session, NULL, 0, NULL, 0) < 0) return RLM_MODULE_FAIL;
return RLM_MODULE_OK;
/*
break;
case RLM_MODULE_OK:
+ {
+ static char keying_prf_label[] = "client EAP encryption";
+
/*
* Success: Automatically return MPPE keys.
*/
- if (eap_tls_success(eap_session, "client EAP encryption") < 0) return 0;
+ if (eap_tls_success(eap_session,
+ keying_prf_label, sizeof(keying_prf_label) - 1,
+ NULL, 0) < 0) return 0;
+ }
break;
/*
*/
case EAP_TLS_ESTABLISHED:
{
- char const *prf_label = NULL;
-
if (inst->virtual_server) return eap_tls_virtual_server(inst, eap_session);
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
case TLS1_1_VERSION:
case TLS1_2_VERSION:
#endif
- prf_label = "client EAP encryption";
+ {
+ static char const keying_prf_label[] = "client EAP encryption";
+
+ if (eap_tls_success(eap_session,
+ keying_prf_label, sizeof(keying_prf_label) - 1,
+ NULL, 0) < 0) return RLM_MODULE_FAIL;
+ }
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
break;
case TLS1_3_VERSION:
default:
- prf_label = "EXPORTER_EAP_TLS_Key_Material";
+ {
+ static char const keying_prf_label[] = "EXPORTER_EAP_TLS_Key_Material";
+ static char const sessid_prf_label[] = "EXPORTER_EAP_TLS_Method-Id";
+
+ if (eap_tls_success(eap_session,
+ keying_prf_label, sizeof(keying_prf_label) - 1,
+ sessid_prf_label, sizeof(sessid_prf_label) - 1) < 0) return RLM_MODULE_FAIL;
+ }
break;
#endif
}
- if (eap_tls_success(eap_session, prf_label) < 0) return RLM_MODULE_FAIL;
+
}
return RLM_MODULE_OK;
tls_session_t *tls_session = eap_tls_session->tls_session;
ttls_tunnel_t *tunnel = NULL;
REQUEST *request = eap_session->request;
+ static char keying_prf_label[] = "ttls keying material";
if (tls_session->opaque) tunnel = talloc_get_type_abort(tls_session->opaque, ttls_tunnel_t);
}
if (tunnel && tunnel->authenticated) {
+
do_keys:
/*
* Success: Automatically return MPPE keys.
*/
- if (eap_tls_success(eap_session, "ttls keying material") < 0) return RLM_MODULE_FAIL;
+ if (eap_tls_success(eap_session,
+ keying_prf_label, sizeof(keying_prf_label) - 1,
+ NULL, 0) < 0) return RLM_MODULE_FAIL;
return RLM_MODULE_OK;
} else {
eap_tls_request(eap_session);
goto error;
}
- eap_tls_gen_challenge(ssl, challenge, scratch,
+ eap_crypto_challenge(ssl, challenge, scratch,
sizeof(challenge), "ttls challenge");
if (memcmp(challenge, vp->vp_octets, vp->vp_length) != 0) {