Fixes from clang / scan-build
[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 #include <freeradius-devel/ident.h>
26 RCSID("$Id$")
27
28 #include <openssl/hmac.h>
29 #include "eap_tls.h"
30
31 /*
32  * Add value pair to reply
33  */
34 static void add_reply(VALUE_PAIR** vp,
35                       const char* name, const uint8_t * value, int len)
36 {
37         VALUE_PAIR *reply_attr;
38         reply_attr = pairmake(name, "", T_OP_EQ);
39         if (!reply_attr) {
40                 DEBUG("rlm_eap_tls: "
41                       "add_reply failed to create attribute %s: %s\n",
42                       name, fr_strerror());
43                 return;
44         }
45
46         memcpy(reply_attr->vp_octets, value, len);
47         reply_attr->length = len;
48         pairadd(vp, reply_attr);
49 }
50
51 /*
52  * TLS PRF from RFC 2246
53  */
54 static void P_hash(const EVP_MD *evp_md,
55                    const unsigned char *secret, unsigned int secret_len,
56                    const unsigned char *seed,   unsigned int seed_len,
57                    unsigned char *out, unsigned int out_len)
58 {
59         HMAC_CTX ctx_a, ctx_out;
60         unsigned char a[HMAC_MAX_MD_CBLOCK];
61         unsigned int size;
62
63         HMAC_CTX_init(&ctx_a);
64         HMAC_CTX_init(&ctx_out);
65         HMAC_Init_ex(&ctx_a, secret, secret_len, evp_md, NULL);
66         HMAC_Init_ex(&ctx_out, secret, secret_len, evp_md, NULL);
67
68         size = HMAC_size(&ctx_out);
69
70         /* Calculate A(1) */
71         HMAC_Update(&ctx_a, seed, seed_len);
72         HMAC_Final(&ctx_a, a, NULL);
73
74         while (1) {
75                 /* Calculate next part of output */
76                 HMAC_Update(&ctx_out, a, size);
77                 HMAC_Update(&ctx_out, seed, seed_len);
78
79                 /* Check if last part */
80                 if (out_len < size) {
81                         HMAC_Final(&ctx_out, a, NULL);
82                         memcpy(out, a, out_len);
83                         break;
84                 }
85
86                 /* Place digest in output buffer */
87                 HMAC_Final(&ctx_out, out, NULL);
88                 HMAC_Init_ex(&ctx_out, NULL, 0, NULL, NULL);
89                 out += size;
90                 out_len -= size;
91
92                 /* Calculate next A(i) */
93                 HMAC_Init_ex(&ctx_a, NULL, 0, NULL, NULL);
94                 HMAC_Update(&ctx_a, a, size);
95                 HMAC_Final(&ctx_a, a, NULL);
96         }
97
98         HMAC_CTX_cleanup(&ctx_a);
99         HMAC_CTX_cleanup(&ctx_out);
100         memset(a, 0, sizeof(a));
101 }
102
103 static void PRF(const unsigned char *secret, unsigned int secret_len,
104                 const unsigned char *seed,   unsigned int seed_len,
105                 unsigned char *out, unsigned char *buf, unsigned int out_len)
106 {
107         unsigned int i;
108         unsigned int len = (secret_len + 1) / 2;
109         const unsigned char *s1 = secret;
110         const unsigned char *s2 = secret + (secret_len - len);
111
112         P_hash(EVP_md5(),  s1, len, seed, seed_len, out, out_len);
113         P_hash(EVP_sha1(), s2, len, seed, seed_len, buf, out_len);
114
115         for (i=0; i < out_len; i++) {
116                 out[i] ^= buf[i];
117         }
118 }
119
120 #define EAPTLS_MPPE_KEY_LEN     32
121
122 #define EAPTLS_PRF_LABEL "ttls keying material"
123
124 /*
125  *      Generate keys according to RFC 2716 and add to reply
126  */
127 void eaptls_gen_mppe_keys(VALUE_PAIR **reply_vps, SSL *s,
128                           const char *prf_label)
129 {
130         unsigned char out[4*EAPTLS_MPPE_KEY_LEN], buf[4*EAPTLS_MPPE_KEY_LEN];
131         unsigned char seed[64 + 2*SSL3_RANDOM_SIZE];
132         unsigned char *p = seed;
133         size_t prf_size;
134
135         prf_size = strlen(prf_label);
136
137         memcpy(p, prf_label, prf_size);
138         p += prf_size;
139
140         memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
141         p += SSL3_RANDOM_SIZE;
142         prf_size += SSL3_RANDOM_SIZE;
143
144         memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE);
145         prf_size += SSL3_RANDOM_SIZE;
146
147         PRF(s->session->master_key, s->session->master_key_length,
148             seed, prf_size, out, buf, sizeof(out));
149
150         p = out;
151         add_reply(reply_vps, "MS-MPPE-Recv-Key", p, EAPTLS_MPPE_KEY_LEN);
152         p += EAPTLS_MPPE_KEY_LEN;
153         add_reply(reply_vps, "MS-MPPE-Send-Key", p, EAPTLS_MPPE_KEY_LEN);
154
155         add_reply(reply_vps, "EAP-MSK", out, 64);
156         add_reply(reply_vps, "EAP-EMSK", out + 64, 64);
157 }
158
159
160 #define EAPTLS_PRF_CHALLENGE        "ttls challenge"
161
162 /*
163  *      Generate the TTLS challenge
164  *
165  *      It's in the TLS module simply because it's only a few lines
166  *      of code, and it needs access to the TLS PRF functions.
167  */
168 void eapttls_gen_challenge(SSL *s, uint8_t *buffer, size_t size)
169 {
170         uint8_t out[32], buf[32];
171         uint8_t seed[sizeof(EAPTLS_PRF_CHALLENGE)-1 + 2*SSL3_RANDOM_SIZE];
172         uint8_t *p = seed;
173
174         memcpy(p, EAPTLS_PRF_CHALLENGE, sizeof(EAPTLS_PRF_CHALLENGE)-1);
175         p += sizeof(EAPTLS_PRF_CHALLENGE)-1;
176         memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
177         p += SSL3_RANDOM_SIZE;
178         memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE);
179
180         PRF(s->session->master_key, s->session->master_key_length,
181             seed, sizeof(seed), out, buf, sizeof(out));
182
183         memcpy(buffer, out, size);
184 }