The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: 3f2145ae9ddcdc921489fa204c8300ebf3cc0624 $
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  */
27 RCSID("$Id: 3f2145ae9ddcdc921489fa204c8300ebf3cc0624 $")
28 USES_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 <freeradius-devel/tls/openssl_user_macros.h>
35 #include <openssl/evp.h>
36 #include <openssl/aes.h>
37 #include <openssl/err.h>
38 
39 #include "eap_fast_crypto.h"
40 
41 /* EAP-FAST Pseudo-Random Function (T-PRF): RFC 4851, Section 5.5 */
42 void T_PRF(unsigned char const *secret, unsigned int secret_len,
43  char const *prf_label,
44  unsigned char const *seed, unsigned int seed_len,
45  unsigned char *out, unsigned int out_len)
46 {
47  size_t prf_size = strlen(prf_label);
48  size_t pos;
49  uint8_t *buf;
50 
51  if (prf_size > 128) prf_size = 128;
52  prf_size++; /* include trailing zero */
53 
54  buf = talloc_size(NULL, SHA1_DIGEST_LENGTH + prf_size + seed_len + 2 + 1);
55 
56  memcpy(buf + SHA1_DIGEST_LENGTH, prf_label, prf_size);
57  if (seed) memcpy(buf + SHA1_DIGEST_LENGTH + prf_size, seed, seed_len);
58  *(uint16_t *)&buf[SHA1_DIGEST_LENGTH + prf_size + seed_len] = htons(out_len);
59  buf[SHA1_DIGEST_LENGTH + prf_size + seed_len + 2] = 1;
60 
61  // T1 is just the seed
62  fr_hmac_sha1(buf, buf + SHA1_DIGEST_LENGTH, prf_size + seed_len + 2 + 1, secret, secret_len);
63 
64 #define MIN(a,b) (((a)>(b)) ? (b) : (a))
65  memcpy(out, buf, MIN(out_len, SHA1_DIGEST_LENGTH));
66 
67  pos = SHA1_DIGEST_LENGTH;
68  while (pos < out_len) {
69  buf[SHA1_DIGEST_LENGTH + prf_size + seed_len + 2]++;
70 
71  fr_hmac_sha1(buf, buf, SHA1_DIGEST_LENGTH + prf_size + seed_len + 2 + 1, secret, secret_len);
72  memcpy(&out[pos], buf, MIN(out_len - pos, SHA1_DIGEST_LENGTH));
73 
74  if (out_len - pos <= SHA1_DIGEST_LENGTH)
75  break;
76 
77  pos += SHA1_DIGEST_LENGTH;
78  }
79 
80  memset(buf, 0, SHA1_DIGEST_LENGTH + prf_size + seed_len + 2 + 1);
81  talloc_free(buf);
82 }
83 
84 // http://stackoverflow.com/a/29838852
85 static NEVER_RETURNS void handleErrors(void)
86 {
87  unsigned long errCode;
88 
89  fprintf(stderr, "An error occurred\n");
90  while((errCode = ERR_get_error()))
91  {
92  char *err = ERR_error_string(errCode, NULL);
93  fprintf(stderr, "%s\n", err);
94  }
95  abort();
96 }
97 
98 // https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption#Authenticated_Encryption_using_GCM_mode
99 int eap_fast_encrypt(uint8_t const *plaintext, size_t plaintext_len,
100  uint8_t const *aad, size_t aad_len,
101  uint8_t const *key, uint8_t *iv, unsigned char *ciphertext,
102  uint8_t *tag)
103 {
104  EVP_CIPHER_CTX *ctx;
105 
106  int len;
107 
108  int ciphertext_len;
109 
110 
111  /* Create and initialise the context */
112  if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
113 
114  /* Initialise the encryption operation. */
115  if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
116  handleErrors();
117 
118  /* Set IV length if default 12 bytes (96 bits) is not appropriate */
119  if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL))
120  handleErrors();
121 
122  /* Initialise key and IV */
123  if (1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors();
124 
125  /* Provide any AAD data. This can be called zero or more times as
126  * required
127  */
128  if (1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
129  handleErrors();
130 
131  /* Provide the message to be encrypted, and obtain the encrypted output.
132  * EVP_EncryptUpdate can be called multiple times if necessary
133  */
134  if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
135  handleErrors();
136  ciphertext_len = len;
137 
138  /* Finalise the encryption. Normally ciphertext bytes may be written at
139  * this stage, but this does not occur in GCM mode
140  */
141  if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
142  ciphertext_len += len;
143 
144  /* Get the tag */
145  if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
146  handleErrors();
147 
148  /* Clean up */
149  EVP_CIPHER_CTX_free(ctx);
150 
151  return ciphertext_len;
152 }
153 
154 int eap_fast_decrypt(uint8_t const *ciphertext, size_t ciphertext_len,
155  uint8_t const *aad, size_t aad_len,
156  uint8_t const *tag, uint8_t const *key, uint8_t const *iv, uint8_t *plaintext)
157 {
158  EVP_CIPHER_CTX *ctx;
159  int len;
160  int plaintext_len;
161  int ret;
162 
163  /* Create and initialise the context */
164  if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
165 
166  /* Initialise the decryption operation. */
167  if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
168  handleErrors();
169 
170  /* Set IV length. Not necessary if this is 12 bytes (96 bits) */
171  if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL))
172  handleErrors();
173 
174  /* Initialise key and IV */
175  if (!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors();
176 
177  /* Provide any AAD data. This can be called zero or more times as
178  * required
179  */
180  if (!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
181  handleErrors();
182 
183  /* Provide the message to be decrypted, and obtain the plaintext output.
184  * EVP_DecryptUpdate can be called multiple times if necessary
185  */
186  if (!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
187  handleErrors();
188  plaintext_len = len;
189 
190  {
191  unsigned char *tmp;
192 
193  memcpy(&tmp, &tag, sizeof(tmp));
194 
195  /* Set expected tag value. Works in OpenSSL 1.0.1d and later */
196  if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tmp)) handleErrors();
197  }
198 
199  /* Finalise the decryption. A positive return value indicates success,
200  * anything else is a failure - the plaintext is not trustworthy.
201  */
202  ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
203 
204  /* Clean up */
205  EVP_CIPHER_CTX_free(ctx);
206 
207  if (ret > 0)
208  {
209  /* Success */
210  plaintext_len += len;
211  return plaintext_len;
212  }
213  else
214  {
215  /* Verify failed */
216  return -1;
217  }
218 }
219 
220 
221 static void crypto_rfc4346_p_hash(uint8_t *out, size_t out_len,
222  EVP_MD const *evp_md,
223  uint8_t const *secret, size_t secret_len,
224  uint8_t const *seed, size_t seed_len)
225 {
226  EVP_MD_CTX *ctx_a, *ctx_out;
227  EVP_PKEY *pkey;
228 
229  uint8_t a[EVP_MAX_MD_SIZE];
230  size_t size;
231 
232  ctx_a = EVP_MD_CTX_new();
233  ctx_out = EVP_MD_CTX_new();
234 
235  MEM(pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, secret, secret_len));
236 
237  EVP_DigestSignInit(ctx_a, NULL, evp_md, NULL, pkey);
238  EVP_DigestSignInit(ctx_out, NULL, evp_md, NULL, pkey);
239 
240  size = EVP_MD_size(evp_md);
241 
242  /* Calculate A(1) */
243  EVP_DigestSignUpdate(ctx_a, seed, seed_len);
244 
245  /*
246  * OpenSSL <= 1.1.1 requires a non-null pointer for len
247  */
248  EVP_DigestSignFinal(ctx_a, a, &(size_t){ sizeof(a) });
249 
250  while (1) {
251  /* Calculate next part of output */
252  EVP_DigestSignUpdate(ctx_out, a, size);
253  EVP_DigestSignUpdate(ctx_out, seed, seed_len);
254 
255  /* Check if last part */
256  if (out_len < size) {
257  EVP_DigestSignFinal(ctx_out, a, &(size_t){ sizeof(a) });
258  memcpy(out, a, out_len);
259  break;
260  }
261 
262  /* Place digest in output buffer */
263  EVP_DigestSignFinal(ctx_out, out, &(size_t){ EVP_MAX_MD_SIZE });
264  EVP_MD_CTX_reset(ctx_out);
265 
266  EVP_DigestSignInit(ctx_out, NULL, evp_md, NULL, pkey);
267  out += size;
268  out_len -= size;
269 
270  /* Calculate next A(i) */
271  EVP_MD_CTX_reset(ctx_a);
272  EVP_DigestSignInit(ctx_a, NULL, evp_md, NULL, pkey);
273  EVP_DigestSignUpdate(ctx_a, a, size);
274  EVP_DigestSignFinal(ctx_a, a, &(size_t){ EVP_MAX_MD_SIZE });
275  }
276 
277  EVP_PKEY_free(pkey);
278 
279  EVP_MD_CTX_free(ctx_a);
280  EVP_MD_CTX_free(ctx_out);
281 #ifdef __STDC_LIB_EXT1__
282  memset_s(a, 0, sizeof(a), sizeof(a));
283 #else
284  memset(a, 0, sizeof(a));
285 #endif
286 }
287 
288 
289 static void eap_crypto_rfc4346_prf(uint8_t *out, size_t out_len, uint8_t *scratch,
290  uint8_t const *secret, size_t secret_len,
291  uint8_t const *seed, size_t seed_len)
292 {
293  unsigned int i;
294  unsigned int len = (secret_len + 1) / 2;
295  uint8_t const *s1 = secret;
296  uint8_t const *s2 = secret + (secret_len - len);
297 
298  crypto_rfc4346_p_hash(out, out_len, EVP_md5(), s1, len, seed, seed_len);
299  crypto_rfc4346_p_hash(scratch, out_len, EVP_sha1(), s2, len, seed, seed_len);
300 
301  for (i = 0; i < out_len; i++) out[i] ^= scratch[i];
302 }
303 
304 
305 /*
306  * Same as before, but for EAP-FAST the order of {server,client}_random is flipped
307  */
308 void eap_fast_tls_gen_challenge(SSL *s, uint8_t *buffer, uint8_t *scratch, size_t size, char const *prf_label)
309 {
310  uint8_t *p;
311  size_t len, master_key_len;
312  uint8_t seed[128 + (2 * SSL3_RANDOM_SIZE)];
313  uint8_t master_key[SSL_MAX_MASTER_KEY_LENGTH];
314 
315  len = strlen(prf_label);
316  if (len > 128) len = 128;
317 
318  p = seed;
319  memcpy(p, prf_label, len);
320  p += len;
321  (void) SSL_get_server_random(s, p, SSL3_RANDOM_SIZE);
322  p += SSL3_RANDOM_SIZE;
323  (void) SSL_get_client_random(s, p, SSL3_RANDOM_SIZE);
324  p += SSL3_RANDOM_SIZE;
325 
326  master_key_len = SSL_SESSION_get_master_key(SSL_get_session(s), master_key, sizeof(master_key));
327  eap_crypto_rfc4346_prf(buffer, size, scratch, master_key, master_key_len, seed, p - seed);
328 }
static int const char char buffer[256]
Definition: acutest.h:574
#define USES_APPLE_DEPRECATED_API
Definition: build.h:468
#define RCSID(id)
Definition: build.h:481
#define NEVER_RETURNS
Should be placed before the function return type.
Definition: build.h:311
static fr_slen_t err
Definition: dict.h:821
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.
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:124
talloc_free(reap)
unsigned short uint16_t
Definition: merged_model.c:31
unsigned char uint8_t
Definition: merged_model.c:30
static char * secret
Definition: radclient-ng.c:69
#define SHA1_DIGEST_LENGTH
Definition: sha1.h:29
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
static size_t char ** out
Definition: value.h:997