1 /*
2 * TLSv1 credentials
3 * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9 #include "utils/includes.h"
10
11 #include "utils/common.h"
12 #include "utils/base64.h"
13 #include "crypto/crypto.h"
14 #include "tls/x509v3.h"
15 #include "tls/tlsv1_cred.h"
16
tlsv1_cred_alloc(void)17 struct tlsv1_credentials * tlsv1_cred_alloc(void)
18 {
19 struct tlsv1_credentials *cred;
20 cred = (struct tlsv1_credentials *)os_zalloc(sizeof(*cred));
21 return cred;
22 }
23
24
tlsv1_cred_free(struct tlsv1_credentials * cred)25 void tlsv1_cred_free(struct tlsv1_credentials *cred)
26 {
27 if (cred == NULL)
28 return;
29
30 x509_certificate_chain_free(cred->trusted_certs);
31 x509_certificate_chain_free(cred->cert);
32 crypto_private_key_free(cred->key);
33 os_free(cred->dh_p);
34 os_free(cred->dh_g);
35 os_free(cred);
36 }
37
38
tlsv1_add_cert_der(struct x509_certificate ** chain,const u8 * buf,size_t len)39 static int tlsv1_add_cert_der(struct x509_certificate **chain,
40 const u8 *buf, size_t len)
41 {
42 struct x509_certificate *cert, *p;
43 char name[128];
44
45 cert = x509_certificate_parse(buf, len);
46 if (cert == NULL) {
47 wpa_printf(MSG_INFO, "TLSv1: %s - failed to parse certificate",
48 __func__);
49 return -1;
50 }
51
52 p = *chain;
53 while (p && p->next)
54 p = p->next;
55 if (p && x509_name_compare(&cert->subject, &p->issuer) == 0) {
56 /*
57 * The new certificate is the issuer of the last certificate in
58 * the chain - add the new certificate to the end.
59 */
60 p->next = cert;
61 } else {
62 /* Add to the beginning of the chain */
63 cert->next = *chain;
64 *chain = cert;
65 }
66
67 x509_name_string(&cert->subject, name, sizeof(name));
68 wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name);
69
70 return 0;
71 }
72
73
74 static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----";
75 static const char *pem_cert_end = "-----END CERTIFICATE-----";
76 static const char *pem_key_begin = "-----BEGIN RSA PRIVATE KEY-----";
77 static const char *pem_key_end = "-----END RSA PRIVATE KEY-----";
78 static const char *pem_key2_begin = "-----BEGIN PRIVATE KEY-----";
79 static const char *pem_key2_end = "-----END PRIVATE KEY-----";
80 static const char *pem_key_enc_begin = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
81 static const char *pem_key_enc_end = "-----END ENCRYPTED PRIVATE KEY-----";
82
83
search_tag(const char * tag,const u8 * buf,size_t len)84 static const u8 * search_tag(const char *tag, const u8 *buf, size_t len)
85 {
86 size_t i, plen;
87
88 plen = os_strlen(tag);
89 if (len < plen)
90 return NULL;
91
92 for (i = 0; i < len - plen; i++) {
93 if (os_memcmp(buf + i, tag, plen) == 0)
94 return buf + i;
95 }
96
97 return NULL;
98 }
99
100
tlsv1_add_cert(struct x509_certificate ** chain,const u8 * buf,size_t len)101 static int tlsv1_add_cert(struct x509_certificate **chain,
102 const u8 *buf, size_t len)
103 {
104 const u8 *pos, *end;
105 unsigned char *der;
106 size_t der_len;
107
108 pos = search_tag(pem_cert_begin, buf, len);
109 if (!pos) {
110 wpa_printf(MSG_DEBUG, "TLSv1: No PEM certificate tag found - "
111 "assume DER format");
112 return tlsv1_add_cert_der(chain, buf, len);
113 }
114
115 wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format certificate into "
116 "DER format");
117
118 while (pos) {
119 pos += os_strlen(pem_cert_begin);
120 end = search_tag(pem_cert_end, pos, buf + len - pos);
121 if (end == NULL) {
122 wpa_printf(MSG_INFO, "TLSv1: Could not find PEM "
123 "certificate end tag (%s)", pem_cert_end);
124 return -1;
125 }
126
127 der = (unsigned char *)base64_decode((const char *)pos, end - pos, &der_len);
128 if (der == NULL) {
129 wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
130 "certificate");
131 return -1;
132 }
133
134 if (tlsv1_add_cert_der(chain, der, der_len) < 0) {
135 wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM "
136 "certificate after DER conversion");
137 os_free(der);
138 return -1;
139 }
140
141 os_free(der);
142
143 end += os_strlen(pem_cert_end);
144 pos = search_tag(pem_cert_begin, end, buf + len - end);
145 }
146
147 return 0;
148 }
149
150
tlsv1_set_cert_chain(struct x509_certificate ** chain,const char * cert,const u8 * cert_blob,size_t cert_blob_len)151 static int tlsv1_set_cert_chain(struct x509_certificate **chain,
152 const char *cert, const u8 *cert_blob,
153 size_t cert_blob_len)
154 {
155 if (cert_blob)
156 return tlsv1_add_cert(chain, cert_blob, cert_blob_len);
157
158 if (cert) {
159 u8 *buf = NULL;
160 size_t len = 0;
161 int ret;
162
163 if (buf == NULL) {
164 wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
165 cert);
166 return -1;
167 }
168
169 ret = tlsv1_add_cert(chain, buf, len);
170 os_free(buf);
171 return ret;
172 }
173
174 return 0;
175 }
176
177
178 /**
179 * tlsv1_set_ca_cert - Set trusted CA certificate(s)
180 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
181 * @cert: File or reference name for X.509 certificate in PEM or DER format
182 * @cert_blob: cert as inlined data or %NULL if not used
183 * @cert_blob_len: ca_cert_blob length
184 * @path: Path to CA certificates (not yet supported)
185 * Returns: 0 on success, -1 on failure
186 */
tlsv1_set_ca_cert(struct tlsv1_credentials * cred,const char * cert,const u8 * cert_blob,size_t cert_blob_len,const char * path)187 int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
188 const u8 *cert_blob, size_t cert_blob_len,
189 const char *path)
190 {
191 if (tlsv1_set_cert_chain(&cred->trusted_certs, cert,
192 cert_blob, cert_blob_len) < 0)
193 return -1;
194
195 if (path) {
196 /* TODO: add support for reading number of certificate files */
197 wpa_printf(MSG_INFO, "TLSv1: Use of CA certificate directory "
198 "not yet supported");
199 return -1;
200 }
201
202 return 0;
203 }
204
205
206 /**
207 * tlsv1_set_cert - Set certificate
208 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
209 * @cert: File or reference name for X.509 certificate in PEM or DER format
210 * @cert_blob: cert as inlined data or %NULL if not used
211 * @cert_blob_len: cert_blob length
212 * Returns: 0 on success, -1 on failure
213 */
tlsv1_set_cert(struct tlsv1_credentials * cred,const char * cert,const u8 * cert_blob,size_t cert_blob_len)214 int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert,
215 const u8 *cert_blob, size_t cert_blob_len)
216 {
217 return tlsv1_set_cert_chain(&cred->cert, cert,
218 cert_blob, cert_blob_len);
219 }
220
221
tlsv1_set_key_pem(const u8 * key,size_t len)222 static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len)
223 {
224 const u8 *pos, *end;
225 unsigned char *der;
226 size_t der_len;
227 struct crypto_private_key *pkey;
228
229 pos = search_tag(pem_key_begin, key, len);
230 if (!pos) {
231 pos = search_tag(pem_key2_begin, key, len);
232 if (!pos)
233 return NULL;
234 pos += os_strlen(pem_key2_begin);
235 end = search_tag(pem_key2_end, pos, key + len - pos);
236 if (!end)
237 return NULL;
238 } else {
239 const u8 *pos2;
240 pos += os_strlen(pem_key_begin);
241 end = search_tag(pem_key_end, pos, key + len - pos);
242 if (!end)
243 return NULL;
244 pos2 = search_tag("Proc-Type: 4,ENCRYPTED", pos, end - pos);
245 if (pos2) {
246 wpa_printf(MSG_DEBUG, "TLSv1: Unsupported private key "
247 "format (Proc-Type/DEK-Info)");
248 return NULL;
249 }
250 }
251
252 der = (unsigned char *)base64_decode((const char *)pos, end - pos, &der_len);
253 if (!der)
254 return NULL;
255 pkey = crypto_private_key_import(der, der_len, NULL);
256 os_free(der);
257 return pkey;
258 }
259
260
tlsv1_set_key_enc_pem(const u8 * key,size_t len,const char * passwd)261 static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key,
262 size_t len,
263 const char *passwd)
264 {
265 const u8 *pos, *end;
266 unsigned char *der;
267 size_t der_len;
268 struct crypto_private_key *pkey;
269
270 if (passwd == NULL)
271 return NULL;
272 pos = search_tag(pem_key_enc_begin, key, len);
273 if (!pos)
274 return NULL;
275 pos += os_strlen(pem_key_enc_begin);
276 end = search_tag(pem_key_enc_end, pos, key + len - pos);
277 if (!end)
278 return NULL;
279
280 der = (unsigned char *)base64_decode((const char *)pos, end - pos, &der_len);
281 if (!der)
282 return NULL;
283 pkey = crypto_private_key_import(der, der_len, passwd);
284 os_free(der);
285 return pkey;
286 }
287
288
tlsv1_set_key(struct tlsv1_credentials * cred,const u8 * key,size_t len,const char * passwd)289 static int tlsv1_set_key(struct tlsv1_credentials *cred,
290 const u8 *key, size_t len, const char *passwd)
291 {
292 cred->key = crypto_private_key_import(key, len, passwd);
293 if (cred->key == NULL)
294 cred->key = tlsv1_set_key_pem(key, len);
295 if (cred->key == NULL)
296 cred->key = tlsv1_set_key_enc_pem(key, len, passwd);
297 if (cred->key == NULL) {
298 wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
299 return -1;
300 }
301 return 0;
302 }
303
304
305 /**
306 * tlsv1_set_private_key - Set private key
307 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
308 * @private_key: File or reference name for the key in PEM or DER format
309 * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
310 * passphrase is used.
311 * @private_key_blob: private_key as inlined data or %NULL if not used
312 * @private_key_blob_len: private_key_blob length
313 * Returns: 0 on success, -1 on failure
314 */
tlsv1_set_private_key(struct tlsv1_credentials * cred,const char * private_key,const char * private_key_passwd,const u8 * private_key_blob,size_t private_key_blob_len)315 int tlsv1_set_private_key(struct tlsv1_credentials *cred,
316 const char *private_key,
317 const char *private_key_passwd,
318 const u8 *private_key_blob,
319 size_t private_key_blob_len)
320 {
321 crypto_private_key_free(cred->key);
322 cred->key = NULL;
323
324 if (private_key_blob)
325 return tlsv1_set_key(cred, private_key_blob,
326 private_key_blob_len,
327 private_key_passwd);
328
329 if (private_key) {
330 u8 *buf = NULL;
331 size_t len = 0;
332 int ret;
333
334 if (buf == NULL) {
335 wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
336 private_key);
337 return -1;
338 }
339
340 ret = tlsv1_set_key(cred, buf, len, private_key_passwd);
341 os_free(buf);
342 return ret;
343 }
344
345 return 0;
346 }
347
348
tlsv1_set_dhparams_der(struct tlsv1_credentials * cred,const u8 * dh,size_t len)349 static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
350 const u8 *dh, size_t len)
351 {
352 struct asn1_hdr hdr;
353 const u8 *pos, *end;
354
355 pos = dh;
356 end = dh + len;
357
358 /*
359 * DHParameter ::= SEQUENCE {
360 * prime INTEGER, -- p
361 * base INTEGER, -- g
362 * privateValueLength INTEGER OPTIONAL }
363 */
364
365 /* DHParamer ::= SEQUENCE */
366 if (asn1_get_next(pos, len, &hdr) < 0 ||
367 hdr.class != ASN1_CLASS_UNIVERSAL ||
368 hdr.tag != ASN1_TAG_SEQUENCE) {
369 wpa_printf(MSG_DEBUG, "DH: DH parameters did not start with a "
370 "valid SEQUENCE - found class %d tag 0x%x",
371 hdr.class, hdr.tag);
372 return -1;
373 }
374 pos = hdr.payload;
375
376 /* prime INTEGER */
377 if (asn1_get_next(pos, end - pos, &hdr) < 0)
378 return -1;
379
380 if (hdr.class != ASN1_CLASS_UNIVERSAL ||
381 hdr.tag != ASN1_TAG_INTEGER) {
382 wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for p; "
383 "class=%d tag=0x%x", hdr.class, hdr.tag);
384 return -1;
385 }
386
387 wpa_hexdump(MSG_MSGDUMP, "DH: prime (p)", hdr.payload, hdr.length);
388 if (hdr.length == 0)
389 return -1;
390 os_free(cred->dh_p);
391 cred->dh_p = os_malloc(hdr.length);
392 if (cred->dh_p == NULL)
393 return -1;
394 os_memcpy(cred->dh_p, hdr.payload, hdr.length);
395 cred->dh_p_len = hdr.length;
396 pos = hdr.payload + hdr.length;
397
398 /* base INTEGER */
399 if (asn1_get_next(pos, end - pos, &hdr) < 0)
400 return -1;
401
402 if (hdr.class != ASN1_CLASS_UNIVERSAL ||
403 hdr.tag != ASN1_TAG_INTEGER) {
404 wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for g; "
405 "class=%d tag=0x%x", hdr.class, hdr.tag);
406 return -1;
407 }
408
409 wpa_hexdump(MSG_MSGDUMP, "DH: base (g)", hdr.payload, hdr.length);
410 if (hdr.length == 0)
411 return -1;
412 os_free(cred->dh_g);
413 cred->dh_g = os_malloc(hdr.length);
414 if (cred->dh_g == NULL)
415 return -1;
416 os_memcpy(cred->dh_g, hdr.payload, hdr.length);
417 cred->dh_g_len = hdr.length;
418
419 return 0;
420 }
421
422
423 static const char *pem_dhparams_begin = "-----BEGIN DH PARAMETERS-----";
424 static const char *pem_dhparams_end = "-----END DH PARAMETERS-----";
425
426
tlsv1_set_dhparams_blob(struct tlsv1_credentials * cred,const u8 * buf,size_t len)427 static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred,
428 const u8 *buf, size_t len)
429 {
430 const u8 *pos, *end;
431 unsigned char *der;
432 size_t der_len;
433
434 pos = search_tag(pem_dhparams_begin, buf, len);
435 if (!pos) {
436 wpa_printf(MSG_DEBUG, "TLSv1: No PEM dhparams tag found - "
437 "assume DER format");
438 return tlsv1_set_dhparams_der(cred, buf, len);
439 }
440
441 wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format dhparams into DER "
442 "format");
443
444 pos += os_strlen(pem_dhparams_begin);
445 end = search_tag(pem_dhparams_end, pos, buf + len - pos);
446 if (end == NULL) {
447 wpa_printf(MSG_INFO, "TLSv1: Could not find PEM dhparams end "
448 "tag (%s)", pem_dhparams_end);
449 return -1;
450 }
451
452 der = (unsigned char *)base64_decode((const char *)pos, end - pos, &der_len);
453 if (der == NULL) {
454 wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams");
455 return -1;
456 }
457
458 if (tlsv1_set_dhparams_der(cred, der, der_len) < 0) {
459 wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM dhparams "
460 "DER conversion");
461 os_free(der);
462 return -1;
463 }
464
465 os_free(der);
466
467 return 0;
468 }
469
470
471 /**
472 * tlsv1_set_dhparams - Set Diffie-Hellman parameters
473 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
474 * @dh_file: File or reference name for the DH params in PEM or DER format
475 * @dh_blob: DH params as inlined data or %NULL if not used
476 * @dh_blob_len: dh_blob length
477 * Returns: 0 on success, -1 on failure
478 */
tlsv1_set_dhparams(struct tlsv1_credentials * cred,const char * dh_file,const u8 * dh_blob,size_t dh_blob_len)479 int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,
480 const u8 *dh_blob, size_t dh_blob_len)
481 {
482 if (dh_blob)
483 return tlsv1_set_dhparams_blob(cred, dh_blob, dh_blob_len);
484
485 if (dh_file) {
486 u8 *buf = NULL;
487 size_t len = 0;
488 int ret;
489
490 if (buf == NULL) {
491 wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
492 dh_file);
493 return -1;
494 }
495
496 ret = tlsv1_set_dhparams_blob(cred, buf, len);
497 os_free(buf);
498 return ret;
499 }
500
501 return 0;
502 }
503