The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
eap_fast_crypto.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 31786643a249681d459ac1a89c0009a504ecd422 $
19 * @file eap_fast_crypto.c
20 * @brief Cryptographic functions for EAP-FAST.
21 *
22 * @author Alexander Clouter (alex@digriz.org.uk)
23 *
24 * @copyright 2016 Alan DeKok (aland@freeradius.org)
25 * @copyright 2016 The FreeRADIUS server project
26 */
27RCSID("$Id: 31786643a249681d459ac1a89c0009a504ecd422 $")
28USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
29
30#include <stdio.h>
31#include <freeradius-devel/tls/base.h>
32#include <freeradius-devel/eap/tls.h>
33
34#include <openssl/evp.h>
35#include <openssl/aes.h>
36
37#include "eap_fast_crypto.h"
38
39/* EAP-FAST Pseudo-Random Function (T-PRF): RFC 4851, Section 5.5 */
40void T_PRF(unsigned char const *secret, unsigned int secret_len,
41 char const *prf_label,
42 unsigned char const *seed, unsigned int seed_len,
43 unsigned char *out, unsigned int out_len)
44{
45 size_t prf_size = strlen(prf_label);
46 size_t pos;
47 uint8_t *buf;
48
49 if (prf_size > 128) prf_size = 128;
50 prf_size++; /* include trailing zero */
51
52 buf = talloc_size(NULL, SHA1_DIGEST_LENGTH + prf_size + seed_len + 2 + 1);
53
54 memcpy(buf + SHA1_DIGEST_LENGTH, prf_label, prf_size);
55 if (seed) memcpy(buf + SHA1_DIGEST_LENGTH + prf_size, seed, seed_len);
56 *(uint16_t *)&buf[SHA1_DIGEST_LENGTH + prf_size + seed_len] = htons(out_len);
57 buf[SHA1_DIGEST_LENGTH + prf_size + seed_len + 2] = 1;
58
59 // T1 is just the seed
60 fr_hmac_sha1(buf, buf + SHA1_DIGEST_LENGTH, prf_size + seed_len + 2 + 1, secret, secret_len);
61
62#define MIN(a,b) (((a)>(b)) ? (b) : (a))
63 memcpy(out, buf, MIN(out_len, SHA1_DIGEST_LENGTH));
64
66 while (pos < out_len) {
67 buf[SHA1_DIGEST_LENGTH + prf_size + seed_len + 2]++;
68
69 fr_hmac_sha1(buf, buf, SHA1_DIGEST_LENGTH + prf_size + seed_len + 2 + 1, secret, secret_len);
70 memcpy(&out[pos], buf, MIN(out_len - pos, SHA1_DIGEST_LENGTH));
71
72 if (out_len - pos <= SHA1_DIGEST_LENGTH)
73 break;
74
75 pos += SHA1_DIGEST_LENGTH;
76 }
77
78 memset(buf, 0, SHA1_DIGEST_LENGTH + prf_size + seed_len + 2 + 1);
79 talloc_free(buf);
80}
81
82// http://stackoverflow.com/a/29838852
83static NEVER_RETURNS void handleErrors(void)
84{
85 unsigned long errCode;
86
87 fprintf(stderr, "An error occurred\n");
88 while((errCode = ERR_get_error()))
89 {
90 char *err = ERR_error_string(errCode, NULL);
91 fprintf(stderr, "%s\n", err);
92 }
93 abort();
94}
95
96// https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption#Authenticated_Encryption_using_GCM_mode
97int eap_fast_encrypt(uint8_t const *plaintext, size_t plaintext_len,
98 uint8_t const *aad, size_t aad_len,
99 uint8_t const *key, uint8_t *iv, unsigned char *ciphertext,
100 uint8_t *tag)
101{
102 EVP_CIPHER_CTX *ctx;
103
104 int len;
105
106 int ciphertext_len;
107
108
109 /* Create and initialise the context */
110 if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
111
112 /* Initialise the encryption operation. */
113 if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
114 handleErrors();
115
116 /* Set IV length if default 12 bytes (96 bits) is not appropriate */
117 if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL))
118 handleErrors();
119
120 /* Initialise key and IV */
121 if (1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors();
122
123 /* Provide any AAD data. This can be called zero or more times as
124 * required
125 */
126 if (1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
127 handleErrors();
128
129 /* Provide the message to be encrypted, and obtain the encrypted output.
130 * EVP_EncryptUpdate can be called multiple times if necessary
131 */
132 if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
133 handleErrors();
134 ciphertext_len = len;
135
136 /* Finalise the encryption. Normally ciphertext bytes may be written at
137 * this stage, but this does not occur in GCM mode
138 */
139 if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
140 ciphertext_len += len;
141
142 /* Get the tag */
143 if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
144 handleErrors();
145
146 /* Clean up */
147 EVP_CIPHER_CTX_free(ctx);
148
149 return ciphertext_len;
150}
151
152int eap_fast_decrypt(uint8_t const *ciphertext, size_t ciphertext_len,
153 uint8_t const *aad, size_t aad_len,
154 uint8_t const *tag, uint8_t const *key, uint8_t const *iv, uint8_t *plaintext)
155{
156 EVP_CIPHER_CTX *ctx;
157 int len;
158 int plaintext_len;
159 int ret;
160
161 /* Create and initialise the context */
162 if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
163
164 /* Initialise the decryption operation. */
165 if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
166 handleErrors();
167
168 /* Set IV length. Not necessary if this is 12 bytes (96 bits) */
169 if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL))
170 handleErrors();
171
172 /* Initialise key and IV */
173 if (!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors();
174
175 /* Provide any AAD data. This can be called zero or more times as
176 * required
177 */
178 if (!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
179 handleErrors();
180
181 /* Provide the message to be decrypted, and obtain the plaintext output.
182 * EVP_DecryptUpdate can be called multiple times if necessary
183 */
184 if (!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
185 handleErrors();
186 plaintext_len = len;
187
188 {
189 unsigned char *tmp;
190
191 memcpy(&tmp, &tag, sizeof(tmp));
192
193 /* Set expected tag value. Works in OpenSSL 1.0.1d and later */
194 if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tmp)) handleErrors();
195 }
196
197 /* Finalise the decryption. A positive return value indicates success,
198 * anything else is a failure - the plaintext is not trustworthy.
199 */
200 ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
201
202 /* Clean up */
203 EVP_CIPHER_CTX_free(ctx);
204
205 if (ret == 0) return -1;
206
207 /* Success */
208 return plaintext_len + len;
209}
210
211
212static void crypto_rfc4346_p_hash(uint8_t *out, size_t out_len,
213 EVP_MD const *evp_md,
214 uint8_t const *secret, size_t secret_len,
215 uint8_t const *seed, size_t seed_len)
216{
217 EVP_MD_CTX *ctx_a, *ctx_out;
218 EVP_PKEY *pkey;
219
220 uint8_t a[EVP_MAX_MD_SIZE];
221 size_t size;
222
223 ctx_a = EVP_MD_CTX_new();
224 ctx_out = EVP_MD_CTX_new();
225
226 MEM(pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, secret, secret_len));
227
228 EVP_DigestSignInit(ctx_a, NULL, evp_md, NULL, pkey);
229 EVP_DigestSignInit(ctx_out, NULL, evp_md, NULL, pkey);
230
231 size = EVP_MD_size(evp_md);
232
233 /* Calculate A(1) */
234 EVP_DigestSignUpdate(ctx_a, seed, seed_len);
235
236 /*
237 * OpenSSL <= 1.1.1 requires a non-null pointer for len
238 */
239 EVP_DigestSignFinal(ctx_a, a, &(size_t){ sizeof(a) });
240
241 while (1) {
242 /* Calculate next part of output */
243 EVP_DigestSignUpdate(ctx_out, a, size);
244 EVP_DigestSignUpdate(ctx_out, seed, seed_len);
245
246 /* Check if last part */
247 if (out_len < size) {
248 EVP_DigestSignFinal(ctx_out, a, &(size_t){ sizeof(a) });
249 memcpy(out, a, out_len);
250 break;
251 }
252
253 /* Place digest in output buffer */
254 EVP_DigestSignFinal(ctx_out, out, &(size_t){ EVP_MAX_MD_SIZE });
255 EVP_MD_CTX_reset(ctx_out);
256
257 EVP_DigestSignInit(ctx_out, NULL, evp_md, NULL, pkey);
258 out += size;
259 out_len -= size;
260
261 /* Calculate next A(i) */
262 EVP_MD_CTX_reset(ctx_a);
263 EVP_DigestSignInit(ctx_a, NULL, evp_md, NULL, pkey);
264 EVP_DigestSignUpdate(ctx_a, a, size);
265 EVP_DigestSignFinal(ctx_a, a, &(size_t){ EVP_MAX_MD_SIZE });
266 }
267
268 EVP_PKEY_free(pkey);
269
270 EVP_MD_CTX_free(ctx_a);
271 EVP_MD_CTX_free(ctx_out);
272#ifdef __STDC_LIB_EXT1__
273 memset_s(a, 0, sizeof(a), sizeof(a));
274#else
275 memset(a, 0, sizeof(a));
276#endif
277}
278
279
280static void eap_crypto_rfc4346_prf(uint8_t *out, size_t out_len, uint8_t *scratch,
281 uint8_t const *secret, size_t secret_len,
282 uint8_t const *seed, size_t seed_len)
283{
284 unsigned int i;
285 unsigned int len = (secret_len + 1) / 2;
286 uint8_t const *s1 = secret;
287 uint8_t const *s2 = secret + (secret_len - len);
288
289 crypto_rfc4346_p_hash(out, out_len, EVP_md5(), s1, len, seed, seed_len);
290 crypto_rfc4346_p_hash(scratch, out_len, EVP_sha1(), s2, len, seed, seed_len);
291
292 for (i = 0; i < out_len; i++) out[i] ^= scratch[i];
293}
294
295
296/*
297 * Same as before, but for EAP-FAST the order of {server,client}_random is flipped
298 */
299void eap_fast_tls_gen_challenge(SSL *s, uint8_t *buffer, uint8_t *scratch, size_t size, char const *prf_label)
300{
301 uint8_t *p;
302 size_t len, master_key_len;
303 uint8_t seed[128 + (2 * SSL3_RANDOM_SIZE)];
304 uint8_t master_key[SSL_MAX_MASTER_KEY_LENGTH];
305
306 len = strlen(prf_label);
307 if (len > 128) len = 128;
308
309 p = seed;
310 memcpy(p, prf_label, len);
311 p += len;
312 (void) SSL_get_server_random(s, p, SSL3_RANDOM_SIZE);
313 p += SSL3_RANDOM_SIZE;
314 (void) SSL_get_client_random(s, p, SSL3_RANDOM_SIZE);
315 p += SSL3_RANDOM_SIZE;
316
317 master_key_len = SSL_SESSION_get_master_key(SSL_get_session(s), master_key, sizeof(master_key));
318 eap_crypto_rfc4346_prf(buffer, size, scratch, master_key, master_key_len, seed, p - seed);
319}
static int const char char buffer[256]
Definition acutest.h:576
#define USES_APPLE_DEPRECATED_API
Definition build.h:493
#define RCSID(id)
Definition build.h:506
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:334
#define MEM(x)
Definition debug.h:46
static fr_slen_t err
Definition dict.h:882
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)
static NEVER_RETURNS void handleErrors(void)
void eap_fast_tls_gen_challenge(SSL *s, uint8_t *buffer, uint8_t *scratch, size_t size, char const *prf_label)
#define MIN(a, b)
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, uint8_t *tag)
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)
USES_APPLE_DEPRECATED_API 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)
static 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)
Crypto function declarations.
talloc_free(hp)
int fr_hmac_sha1(uint8_t digest[static SHA1_DIGEST_LENGTH], uint8_t const *in, size_t inlen, uint8_t const *key, size_t key_len)
Calculate HMAC using internal SHA1 implementation.
Definition hmac_sha1.c:123
unsigned short uint16_t
unsigned char uint8_t
static char * secret
#define SHA1_DIGEST_LENGTH
Definition sha1.h:29
static size_t char ** out
Definition value.h:1030