6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2002 Axis Communications AB
21 * Copyright 2006 The FreeRADIUS server project
22 * Authors: Henrik Eriksson <henriken@axis.com> & Lars Viklund <larsv@axis.com>
26 USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
29 #include <openssl/hmac.h>
33 * TLS PRF from RFC 2246
35 static void P_hash(EVP_MD const *evp_md,
36 unsigned char const *secret, unsigned int secret_len,
37 unsigned char const *seed, unsigned int seed_len,
38 unsigned char *out, unsigned int out_len)
40 HMAC_CTX ctx_a, ctx_out;
41 unsigned char a[HMAC_MAX_MD_CBLOCK];
44 HMAC_CTX_init(&ctx_a);
45 HMAC_CTX_init(&ctx_out);
46 #ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
47 HMAC_CTX_set_flags(&ctx_a, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
48 HMAC_CTX_set_flags(&ctx_out, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
50 HMAC_Init_ex(&ctx_a, secret, secret_len, evp_md, NULL);
51 HMAC_Init_ex(&ctx_out, secret, secret_len, evp_md, NULL);
53 size = HMAC_size(&ctx_out);
56 HMAC_Update(&ctx_a, seed, seed_len);
57 HMAC_Final(&ctx_a, a, NULL);
60 /* Calculate next part of output */
61 HMAC_Update(&ctx_out, a, size);
62 HMAC_Update(&ctx_out, seed, seed_len);
64 /* Check if last part */
66 HMAC_Final(&ctx_out, a, NULL);
67 memcpy(out, a, out_len);
71 /* Place digest in output buffer */
72 HMAC_Final(&ctx_out, out, NULL);
73 HMAC_Init_ex(&ctx_out, NULL, 0, NULL, NULL);
77 /* Calculate next A(i) */
78 HMAC_Init_ex(&ctx_a, NULL, 0, NULL, NULL);
79 HMAC_Update(&ctx_a, a, size);
80 HMAC_Final(&ctx_a, a, NULL);
83 HMAC_CTX_cleanup(&ctx_a);
84 HMAC_CTX_cleanup(&ctx_out);
85 memset(a, 0, sizeof(a));
88 /* EAP-FAST Pseudo-Random Function (T-PRF): RFC 4851, Section 5.5 */
89 void T_PRF(unsigned char const *secret, unsigned int secret_len,
90 char const *prf_label,
91 unsigned char const *seed, unsigned int seed_len,
92 unsigned char *out, unsigned int out_len)
94 size_t prf_size = strlen(prf_label);
98 if (prf_size > 128) prf_size = 128;
99 prf_size++; /* include trailing zero */
101 buf = talloc_size(NULL, SHA1_DIGEST_LENGTH + prf_size + seed_len + 2 + 1);
103 memcpy(buf + SHA1_DIGEST_LENGTH, prf_label, prf_size);
104 if (seed) memcpy(buf + SHA1_DIGEST_LENGTH + prf_size, seed, seed_len);
105 *(uint16_t *)&buf[SHA1_DIGEST_LENGTH + prf_size + seed_len] = htons(out_len);
106 buf[SHA1_DIGEST_LENGTH + prf_size + seed_len + 2] = 1;
108 // T1 is just the seed
109 fr_hmac_sha1(buf, buf + SHA1_DIGEST_LENGTH, prf_size + seed_len + 2 + 1, secret, secret_len);
111 #define MIN(a,b) (((a)>(b)) ? (b) : (a))
112 memcpy(out, buf, MIN(out_len, SHA1_DIGEST_LENGTH));
114 pos = SHA1_DIGEST_LENGTH;
115 while (pos < out_len) {
116 buf[SHA1_DIGEST_LENGTH + prf_size + seed_len + 2]++;
118 fr_hmac_sha1(buf, buf, SHA1_DIGEST_LENGTH + prf_size + seed_len + 2 + 1, secret, secret_len);
119 memcpy(&out[pos], buf, MIN(out_len - pos, SHA1_DIGEST_LENGTH));
121 if (out_len - pos <= SHA1_DIGEST_LENGTH)
124 pos += SHA1_DIGEST_LENGTH;
127 memset(buf, 0, SHA1_DIGEST_LENGTH + prf_size + seed_len + 2 + 1);
131 static void PRF(unsigned char const *secret, unsigned int secret_len,
132 unsigned char const *seed, unsigned int seed_len,
133 unsigned char *out, unsigned char *buf, unsigned int out_len)
136 unsigned int len = (secret_len + 1) / 2;
137 uint8_t const *s1 = secret;
138 uint8_t const *s2 = secret + (secret_len - len);
140 P_hash(EVP_md5(), s1, len, seed, seed_len, out, out_len);
141 P_hash(EVP_sha1(), s2, len, seed, seed_len, buf, out_len);
143 for (i=0; i < out_len; i++) {
148 #define EAPTLS_MPPE_KEY_LEN 32
151 * Generate keys according to RFC 2716 and add to reply
153 void eaptls_gen_mppe_keys(REQUEST *request, SSL *s, char const *prf_label)
155 uint8_t out[4 * EAPTLS_MPPE_KEY_LEN];
159 prf_size = strlen(prf_label);
161 #if OPENSSL_VERSION_NUMBER >= 0x10001000L
162 if (SSL_export_keying_material(s, out, sizeof(out), prf_label, prf_size, NULL, 0, 0) != 1) {
163 ERROR("Failed generating keying material");
168 uint8_t seed[64 + (2 * SSL3_RANDOM_SIZE)];
169 uint8_t buf[4 * EAPTLS_MPPE_KEY_LEN];
173 memcpy(p, prf_label, prf_size);
176 memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
177 p += SSL3_RANDOM_SIZE;
178 prf_size += SSL3_RANDOM_SIZE;
180 memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE);
181 prf_size += SSL3_RANDOM_SIZE;
183 PRF(s->session->master_key, s->session->master_key_length,
184 seed, prf_size, out, buf, sizeof(out));
189 eap_add_reply(request, "MS-MPPE-Recv-Key", p, EAPTLS_MPPE_KEY_LEN);
190 p += EAPTLS_MPPE_KEY_LEN;
191 eap_add_reply(request, "MS-MPPE-Send-Key", p, EAPTLS_MPPE_KEY_LEN);
193 eap_add_reply(request, "EAP-MSK", out, 64);
194 eap_add_reply(request, "EAP-EMSK", out + 64, 64);
198 #define FR_TLS_PRF_CHALLENGE "ttls challenge"
201 * Generate the TTLS challenge
203 * It's in the TLS module simply because it's only a few lines
204 * of code, and it needs access to the TLS PRF functions.
206 void eapttls_gen_challenge(SSL *s, uint8_t *buffer, size_t size)
208 #if OPENSSL_VERSION_NUMBER >= 0x10001000L
209 SSL_export_keying_material(s, buffer, size, FR_TLS_PRF_CHALLENGE,
210 sizeof(FR_TLS_PRF_CHALLENGE) - 1, NULL, 0, 0);
213 uint8_t out[32], buf[32];
214 uint8_t seed[sizeof(FR_TLS_PRF_CHALLENGE)-1 + 2*SSL3_RANDOM_SIZE];
217 memcpy(p, FR_TLS_PRF_CHALLENGE, sizeof(FR_TLS_PRF_CHALLENGE)-1);
218 p += sizeof(FR_TLS_PRF_CHALLENGE)-1;
219 memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
220 p += SSL3_RANDOM_SIZE;
221 memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE);
223 PRF(s->session->master_key, s->session->master_key_length,
224 seed, sizeof(seed), out, buf, sizeof(out));
225 memcpy(buffer, out, size);
230 * Actually generates EAP-Session-Id, which is an internal server
231 * attribute. Not all systems want to send EAP-Key-Nam
233 void eaptls_gen_eap_key(RADIUS_PACKET *packet, SSL *s, uint32_t header)
238 vp = fr_pair_afrom_num(packet, PW_EAP_SESSION_ID, 0);
241 vp->vp_length = 1 + 2 * SSL3_RANDOM_SIZE;
242 p = talloc_array(vp, uint8_t, vp->vp_length);
244 p[0] = header & 0xff;
246 #ifdef HAVE_SSL_GET_CLIENT_RANDOM
247 SSL_get_client_random(s, p + 1, SSL3_RANDOM_SIZE);
248 SSL_get_server_random(s, p + 1 + SSL3_RANDOM_SIZE, SSL3_RANDOM_SIZE);
250 memcpy(p + 1, s->s3->client_random, SSL3_RANDOM_SIZE);
251 memcpy(p + 1 + SSL3_RANDOM_SIZE,
252 s->s3->server_random, SSL3_RANDOM_SIZE);
255 fr_pair_add(&packet->vps, vp);
259 * Same as before, but for EAP-FAST the order of {server,client}_random is flipped
261 void eap_fast_tls_gen_challenge(SSL *s, uint8_t *buffer, uint8_t *scratch, size_t size, char const *prf_label)
263 uint8_t seed[128 + 2*SSL3_RANDOM_SIZE];
267 len = strlen(prf_label);
268 if (len > 128) len = 128;
270 memcpy(p, prf_label, len);
272 memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE);
273 p += SSL3_RANDOM_SIZE;
274 memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
275 p += SSL3_RANDOM_SIZE;
277 PRF(s->session->master_key, s->session->master_key_length,
278 seed, p - seed, buffer, scratch, size);