Remove redundant file from freeradius-abfab list.
[freeradius.git] / src / modules / rlm_eap / libeap / mppe_keys.c
1 /*
2  * mppe_keys.c
3  *
4  * Version:     $Id$
5  *
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.
10  *
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.
15  *
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
19  *
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>
23  */
24
25 RCSID("$Id$")
26 USES_APPLE_DEPRECATED_API       /* OpenSSL API has been deprecated by Apple */
27
28 #include "eap_tls.h"
29 #include <openssl/hmac.h>
30
31
32 #if OPENSSL_VERSION_NUMBER < 0x10001000L
33 /*
34  * TLS PRF from RFC 2246
35  */
36 static void P_hash(EVP_MD const *evp_md,
37                    unsigned char const *secret, unsigned int secret_len,
38                    unsigned char const *seed,   unsigned int seed_len,
39                    unsigned char *out, unsigned int out_len)
40 {
41         HMAC_CTX ctx_a, ctx_out;
42         unsigned char a[HMAC_MAX_MD_CBLOCK];
43         unsigned int size;
44
45         HMAC_CTX_init(&ctx_a);
46         HMAC_CTX_init(&ctx_out);
47         HMAC_Init_ex(&ctx_a, secret, secret_len, evp_md, NULL);
48         HMAC_Init_ex(&ctx_out, secret, secret_len, evp_md, NULL);
49
50         size = HMAC_size(&ctx_out);
51
52         /* Calculate A(1) */
53         HMAC_Update(&ctx_a, seed, seed_len);
54         HMAC_Final(&ctx_a, a, NULL);
55
56         while (1) {
57                 /* Calculate next part of output */
58                 HMAC_Update(&ctx_out, a, size);
59                 HMAC_Update(&ctx_out, seed, seed_len);
60
61                 /* Check if last part */
62                 if (out_len < size) {
63                         HMAC_Final(&ctx_out, a, NULL);
64                         memcpy(out, a, out_len);
65                         break;
66                 }
67
68                 /* Place digest in output buffer */
69                 HMAC_Final(&ctx_out, out, NULL);
70                 HMAC_Init_ex(&ctx_out, NULL, 0, NULL, NULL);
71                 out += size;
72                 out_len -= size;
73
74                 /* Calculate next A(i) */
75                 HMAC_Init_ex(&ctx_a, NULL, 0, NULL, NULL);
76                 HMAC_Update(&ctx_a, a, size);
77                 HMAC_Final(&ctx_a, a, NULL);
78         }
79
80         HMAC_CTX_cleanup(&ctx_a);
81         HMAC_CTX_cleanup(&ctx_out);
82         memset(a, 0, sizeof(a));
83 }
84
85 static void PRF(unsigned char const *secret, unsigned int secret_len,
86                 unsigned char const *seed,   unsigned int seed_len,
87                 unsigned char *out, unsigned char *buf, unsigned int out_len)
88 {
89         unsigned int i;
90         unsigned int len = (secret_len + 1) / 2;
91         uint8_t const *s1 = secret;
92         uint8_t const *s2 = secret + (secret_len - len);
93
94         P_hash(EVP_md5(),  s1, len, seed, seed_len, out, out_len);
95         P_hash(EVP_sha1(), s2, len, seed, seed_len, buf, out_len);
96
97         for (i=0; i < out_len; i++) {
98                 out[i] ^= buf[i];
99         }
100 }
101 #endif
102
103 #define EAPTLS_MPPE_KEY_LEN     32
104
105 /*
106  *      Generate keys according to RFC 2716 and add to reply
107  */
108 void eaptls_gen_mppe_keys(REQUEST *request, SSL *s, char const *prf_label)
109 {
110         uint8_t out[4 * EAPTLS_MPPE_KEY_LEN];
111         uint8_t *p;
112         size_t prf_size;
113
114         if (!s->s3) {
115                 ERROR("No SSLv3 information");
116                 return;
117         }
118
119         prf_size = strlen(prf_label);
120
121 #if OPENSSL_VERSION_NUMBER >= 0x10001000L
122         if (SSL_export_keying_material(s, out, sizeof(out), prf_label, prf_size, NULL, 0, 0) != 1) {
123                 ERROR("Failed generating keying material");
124                 return;
125         }
126 #else
127         {
128                 uint8_t seed[64 + (2 * SSL3_RANDOM_SIZE)];
129                 uint8_t buf[4 * EAPTLS_MPPE_KEY_LEN];
130
131                 p = seed;
132
133                 memcpy(p, prf_label, prf_size);
134                 p += prf_size;
135
136                 memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
137                 p += SSL3_RANDOM_SIZE;
138                 prf_size += SSL3_RANDOM_SIZE;
139
140                 memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE);
141                 prf_size += SSL3_RANDOM_SIZE;
142
143                 PRF(s->session->master_key, s->session->master_key_length,
144                     seed, prf_size, out, buf, sizeof(out));
145         }
146 #endif
147
148         p = out;
149         eap_add_reply(request, "MS-MPPE-Recv-Key", p, EAPTLS_MPPE_KEY_LEN);
150         p += EAPTLS_MPPE_KEY_LEN;
151         eap_add_reply(request, "MS-MPPE-Send-Key", p, EAPTLS_MPPE_KEY_LEN);
152
153         eap_add_reply(request, "EAP-MSK", out, 64);
154         eap_add_reply(request, "EAP-EMSK", out + 64, 64);
155 }
156
157
158 #define FR_TLS_PRF_CHALLENGE    "ttls challenge"
159
160 /*
161  *      Generate the TTLS challenge
162  *
163  *      It's in the TLS module simply because it's only a few lines
164  *      of code, and it needs access to the TLS PRF functions.
165  */
166 void eapttls_gen_challenge(SSL *s, uint8_t *buffer, size_t size)
167 {
168 #if OPENSSL_VERSION_NUMBER < 0x10001000L
169         uint8_t out[32], buf[32];
170         uint8_t seed[sizeof(FR_TLS_PRF_CHALLENGE)-1 + 2*SSL3_RANDOM_SIZE];
171         uint8_t *p = seed;
172 #endif
173
174         if (!s->s3) {
175                 ERROR("No SSLv3 information");
176                 return;
177         }
178
179 #if OPENSSL_VERSION_NUMBER >= 0x10001000L
180         SSL_export_keying_material(s, buffer, size, FR_TLS_PRF_CHALLENGE,
181                                    sizeof(FR_TLS_PRF_CHALLENGE) - 1, NULL, 0, 0);
182 #else
183         memcpy(p, FR_TLS_PRF_CHALLENGE, sizeof(FR_TLS_PRF_CHALLENGE)-1);
184         p += sizeof(FR_TLS_PRF_CHALLENGE)-1;
185         memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
186         p += SSL3_RANDOM_SIZE;
187         memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE);
188
189         PRF(s->session->master_key, s->session->master_key_length,
190             seed, sizeof(seed), out, buf, sizeof(out));
191
192         memcpy(buffer, out, size);
193 #endif
194 }
195
196 /*
197  *      Actually generates EAP-Session-Id, which is an internal server
198  *      attribute.  Not all systems want to send EAP-Key-Nam
199  */
200 void eaptls_gen_eap_key(RADIUS_PACKET *packet, SSL *s, uint32_t header)
201 {
202         VALUE_PAIR *vp;
203         uint8_t *p;
204
205         if (!s->s3) {
206                 ERROR("No SSLv3 information");
207                 return;
208         }
209
210         vp = fr_pair_afrom_num(packet, PW_EAP_SESSION_ID, 0);
211         if (!vp) return;
212
213         vp->vp_length = 1 + 2 * SSL3_RANDOM_SIZE;
214         p = talloc_array(vp, uint8_t, vp->vp_length);
215
216         p[0] = header & 0xff;
217         memcpy(p + 1, s->s3->client_random, SSL3_RANDOM_SIZE);
218         memcpy(p + 1 + SSL3_RANDOM_SIZE,
219                s->s3->server_random, SSL3_RANDOM_SIZE);
220         vp->vp_octets = p;
221         fr_pair_add(&packet->vps, vp);
222 }