blob: 92f97c7f7f67f128ab9ddd97483fcb5fb264484d [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * TLSv1 credentials
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08003 * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "includes.h"
10
11#include "common.h"
12#include "base64.h"
13#include "crypto/crypto.h"
Dmitry Shmidt55840ad2015-12-14 12:45:46 -080014#include "crypto/sha1.h"
15#include "pkcs5.h"
16#include "pkcs8.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070017#include "x509v3.h"
18#include "tlsv1_cred.h"
19
20
21struct tlsv1_credentials * tlsv1_cred_alloc(void)
22{
23 struct tlsv1_credentials *cred;
24 cred = os_zalloc(sizeof(*cred));
25 return cred;
26}
27
28
29void tlsv1_cred_free(struct tlsv1_credentials *cred)
30{
31 if (cred == NULL)
32 return;
33
34 x509_certificate_chain_free(cred->trusted_certs);
35 x509_certificate_chain_free(cred->cert);
36 crypto_private_key_free(cred->key);
37 os_free(cred->dh_p);
38 os_free(cred->dh_g);
39 os_free(cred);
40}
41
42
43static int tlsv1_add_cert_der(struct x509_certificate **chain,
44 const u8 *buf, size_t len)
45{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080046 struct x509_certificate *cert, *p;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070047 char name[128];
48
49 cert = x509_certificate_parse(buf, len);
50 if (cert == NULL) {
51 wpa_printf(MSG_INFO, "TLSv1: %s - failed to parse certificate",
52 __func__);
53 return -1;
54 }
55
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080056 p = *chain;
57 while (p && p->next)
58 p = p->next;
59 if (p && x509_name_compare(&cert->subject, &p->issuer) == 0) {
60 /*
61 * The new certificate is the issuer of the last certificate in
62 * the chain - add the new certificate to the end.
63 */
64 p->next = cert;
65 } else {
66 /* Add to the beginning of the chain */
67 cert->next = *chain;
68 *chain = cert;
69 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070070
71 x509_name_string(&cert->subject, name, sizeof(name));
72 wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name);
73
74 return 0;
75}
76
77
78static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----";
79static const char *pem_cert_end = "-----END CERTIFICATE-----";
80static const char *pem_key_begin = "-----BEGIN RSA PRIVATE KEY-----";
81static const char *pem_key_end = "-----END RSA PRIVATE KEY-----";
82static const char *pem_key2_begin = "-----BEGIN PRIVATE KEY-----";
83static const char *pem_key2_end = "-----END PRIVATE KEY-----";
84static const char *pem_key_enc_begin = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
85static const char *pem_key_enc_end = "-----END ENCRYPTED PRIVATE KEY-----";
86
87
88static const u8 * search_tag(const char *tag, const u8 *buf, size_t len)
89{
90 size_t i, plen;
91
92 plen = os_strlen(tag);
93 if (len < plen)
94 return NULL;
95
96 for (i = 0; i < len - plen; i++) {
97 if (os_memcmp(buf + i, tag, plen) == 0)
98 return buf + i;
99 }
100
101 return NULL;
102}
103
104
105static int tlsv1_add_cert(struct x509_certificate **chain,
106 const u8 *buf, size_t len)
107{
108 const u8 *pos, *end;
109 unsigned char *der;
110 size_t der_len;
111
112 pos = search_tag(pem_cert_begin, buf, len);
113 if (!pos) {
114 wpa_printf(MSG_DEBUG, "TLSv1: No PEM certificate tag found - "
115 "assume DER format");
116 return tlsv1_add_cert_der(chain, buf, len);
117 }
118
119 wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format certificate into "
120 "DER format");
121
122 while (pos) {
123 pos += os_strlen(pem_cert_begin);
124 end = search_tag(pem_cert_end, pos, buf + len - pos);
125 if (end == NULL) {
126 wpa_printf(MSG_INFO, "TLSv1: Could not find PEM "
127 "certificate end tag (%s)", pem_cert_end);
128 return -1;
129 }
130
131 der = base64_decode(pos, end - pos, &der_len);
132 if (der == NULL) {
133 wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
134 "certificate");
135 return -1;
136 }
137
138 if (tlsv1_add_cert_der(chain, der, der_len) < 0) {
139 wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM "
140 "certificate after DER conversion");
141 os_free(der);
142 return -1;
143 }
144
145 os_free(der);
146
147 end += os_strlen(pem_cert_end);
148 pos = search_tag(pem_cert_begin, end, buf + len - end);
149 }
150
151 return 0;
152}
153
154
155static int tlsv1_set_cert_chain(struct x509_certificate **chain,
156 const char *cert, const u8 *cert_blob,
157 size_t cert_blob_len)
158{
159 if (cert_blob)
160 return tlsv1_add_cert(chain, cert_blob, cert_blob_len);
161
162 if (cert) {
163 u8 *buf;
164 size_t len;
165 int ret;
166
167 buf = (u8 *) os_readfile(cert, &len);
168 if (buf == NULL) {
169 wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
170 cert);
171 return -1;
172 }
173
174 ret = tlsv1_add_cert(chain, buf, len);
175 os_free(buf);
176 return ret;
177 }
178
179 return 0;
180}
181
182
183/**
184 * tlsv1_set_ca_cert - Set trusted CA certificate(s)
185 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
186 * @cert: File or reference name for X.509 certificate in PEM or DER format
187 * @cert_blob: cert as inlined data or %NULL if not used
188 * @cert_blob_len: ca_cert_blob length
189 * @path: Path to CA certificates (not yet supported)
190 * Returns: 0 on success, -1 on failure
191 */
192int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
193 const u8 *cert_blob, size_t cert_blob_len,
194 const char *path)
195{
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -0800196 if (cert && os_strncmp(cert, "hash://", 7) == 0) {
197 const char *pos = cert + 7;
198 if (os_strncmp(pos, "server/sha256/", 14) != 0) {
199 wpa_printf(MSG_DEBUG,
200 "TLSv1: Unsupported ca_cert hash value '%s'",
201 cert);
202 return -1;
203 }
204 pos += 14;
205 if (os_strlen(pos) != 32 * 2) {
206 wpa_printf(MSG_DEBUG,
207 "TLSv1: Unexpected SHA256 hash length in ca_cert '%s'",
208 cert);
209 return -1;
210 }
211 if (hexstr2bin(pos, cred->srv_cert_hash, 32) < 0) {
212 wpa_printf(MSG_DEBUG,
213 "TLSv1: Invalid SHA256 hash value in ca_cert '%s'",
214 cert);
215 return -1;
216 }
217 cred->server_cert_only = 1;
218 cred->ca_cert_verify = 0;
219 wpa_printf(MSG_DEBUG,
220 "TLSv1: Checking only server certificate match");
221 return 0;
222 }
223
224 if (cert && os_strncmp(cert, "probe://", 8) == 0) {
225 cred->cert_probe = 1;
226 cred->ca_cert_verify = 0;
227 wpa_printf(MSG_DEBUG, "TLSv1: Only probe server certificate");
228 return 0;
229 }
230
231 cred->ca_cert_verify = cert || cert_blob || path;
232
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700233 if (tlsv1_set_cert_chain(&cred->trusted_certs, cert,
234 cert_blob, cert_blob_len) < 0)
235 return -1;
236
237 if (path) {
238 /* TODO: add support for reading number of certificate files */
239 wpa_printf(MSG_INFO, "TLSv1: Use of CA certificate directory "
240 "not yet supported");
241 return -1;
242 }
243
244 return 0;
245}
246
247
248/**
249 * tlsv1_set_cert - Set certificate
250 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
251 * @cert: File or reference name for X.509 certificate in PEM or DER format
252 * @cert_blob: cert as inlined data or %NULL if not used
253 * @cert_blob_len: cert_blob length
254 * Returns: 0 on success, -1 on failure
255 */
256int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert,
257 const u8 *cert_blob, size_t cert_blob_len)
258{
259 return tlsv1_set_cert_chain(&cred->cert, cert,
260 cert_blob, cert_blob_len);
261}
262
263
264static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len)
265{
266 const u8 *pos, *end;
267 unsigned char *der;
268 size_t der_len;
269 struct crypto_private_key *pkey;
270
271 pos = search_tag(pem_key_begin, key, len);
272 if (!pos) {
273 pos = search_tag(pem_key2_begin, key, len);
274 if (!pos)
275 return NULL;
276 pos += os_strlen(pem_key2_begin);
277 end = search_tag(pem_key2_end, pos, key + len - pos);
278 if (!end)
279 return NULL;
280 } else {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800281 const u8 *pos2;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700282 pos += os_strlen(pem_key_begin);
283 end = search_tag(pem_key_end, pos, key + len - pos);
284 if (!end)
285 return NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800286 pos2 = search_tag("Proc-Type: 4,ENCRYPTED", pos, end - pos);
287 if (pos2) {
288 wpa_printf(MSG_DEBUG, "TLSv1: Unsupported private key "
289 "format (Proc-Type/DEK-Info)");
290 return NULL;
291 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700292 }
293
294 der = base64_decode(pos, end - pos, &der_len);
295 if (!der)
296 return NULL;
297 pkey = crypto_private_key_import(der, der_len, NULL);
298 os_free(der);
299 return pkey;
300}
301
302
303static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key,
304 size_t len,
305 const char *passwd)
306{
307 const u8 *pos, *end;
308 unsigned char *der;
309 size_t der_len;
310 struct crypto_private_key *pkey;
311
312 if (passwd == NULL)
313 return NULL;
314 pos = search_tag(pem_key_enc_begin, key, len);
315 if (!pos)
316 return NULL;
317 pos += os_strlen(pem_key_enc_begin);
318 end = search_tag(pem_key_enc_end, pos, key + len - pos);
319 if (!end)
320 return NULL;
321
322 der = base64_decode(pos, end - pos, &der_len);
323 if (!der)
324 return NULL;
325 pkey = crypto_private_key_import(der, der_len, passwd);
326 os_free(der);
327 return pkey;
328}
329
330
Dmitry Shmidt55840ad2015-12-14 12:45:46 -0800331#ifdef PKCS12_FUNCS
332
333static int oid_is_rsadsi(struct asn1_oid *oid)
334{
335 return oid->len >= 4 &&
336 oid->oid[0] == 1 /* iso */ &&
337 oid->oid[1] == 2 /* member-body */ &&
338 oid->oid[2] == 840 /* us */ &&
339 oid->oid[3] == 113549 /* rsadsi */;
340}
341
342
343static int pkcs12_is_bagtype_oid(struct asn1_oid *oid, unsigned long type)
344{
345 return oid->len == 9 &&
346 oid_is_rsadsi(oid) &&
347 oid->oid[4] == 1 /* pkcs */ &&
348 oid->oid[5] == 12 /* pkcs-12 */ &&
349 oid->oid[6] == 10 &&
350 oid->oid[7] == 1 /* bagtypes */ &&
351 oid->oid[8] == type;
352}
353
354
355static int is_oid_pkcs7(struct asn1_oid *oid)
356{
357 return oid->len == 7 &&
358 oid->oid[0] == 1 /* iso */ &&
359 oid->oid[1] == 2 /* member-body */ &&
360 oid->oid[2] == 840 /* us */ &&
361 oid->oid[3] == 113549 /* rsadsi */ &&
362 oid->oid[4] == 1 /* pkcs */ &&
363 oid->oid[5] == 7 /* pkcs-7 */;
364}
365
366
367static int is_oid_pkcs7_data(struct asn1_oid *oid)
368{
369 return is_oid_pkcs7(oid) && oid->oid[6] == 1 /* data */;
370}
371
372
373static int is_oid_pkcs7_enc_data(struct asn1_oid *oid)
374{
375 return is_oid_pkcs7(oid) && oid->oid[6] == 6 /* encryptedData */;
376}
377
378
379static int is_oid_pkcs9(struct asn1_oid *oid)
380{
381 return oid->len >= 6 &&
382 oid->oid[0] == 1 /* iso */ &&
383 oid->oid[1] == 2 /* member-body */ &&
384 oid->oid[2] == 840 /* us */ &&
385 oid->oid[3] == 113549 /* rsadsi */ &&
386 oid->oid[4] == 1 /* pkcs */ &&
387 oid->oid[5] == 9 /* pkcs-9 */;
388}
389
390
391static int is_oid_pkcs9_friendly_name(struct asn1_oid *oid)
392{
393 return oid->len == 7 && is_oid_pkcs9(oid) &&
394 oid->oid[6] == 20;
395}
396
397
398static int is_oid_pkcs9_local_key_id(struct asn1_oid *oid)
399{
400 return oid->len == 7 && is_oid_pkcs9(oid) &&
401 oid->oid[6] == 21;
402}
403
404
405static int is_oid_pkcs9_x509_cert(struct asn1_oid *oid)
406{
407 return oid->len == 8 && is_oid_pkcs9(oid) &&
408 oid->oid[6] == 22 /* certTypes */ &&
409 oid->oid[7] == 1 /* x509Certificate */;
410}
411
412
413static int pkcs12_keybag(struct tlsv1_credentials *cred,
414 const u8 *buf, size_t len)
415{
416 /* TODO */
417 return 0;
418}
419
420
421static int pkcs12_pkcs8_keybag(struct tlsv1_credentials *cred,
422 const u8 *buf, size_t len,
423 const char *passwd)
424{
425 struct crypto_private_key *key;
426
427 /* PKCS8ShroudedKeyBag ::= EncryptedPrivateKeyInfo */
428 key = pkcs8_enc_key_import(buf, len, passwd);
429 if (!key)
430 return -1;
431
432 wpa_printf(MSG_DEBUG,
433 "PKCS #12: Successfully decrypted PKCS8ShroudedKeyBag");
434 crypto_private_key_free(cred->key);
435 cred->key = key;
436
437 return 0;
438}
439
440
441static int pkcs12_certbag(struct tlsv1_credentials *cred,
442 const u8 *buf, size_t len)
443{
444 struct asn1_hdr hdr;
445 struct asn1_oid oid;
446 char obuf[80];
447 const u8 *pos, *end;
448
449 /*
450 * CertBag ::= SEQUENCE {
451 * certId BAG-TYPE.&id ({CertTypes}),
452 * certValue [0] EXPLICIT BAG-TYPE.&Type ({CertTypes}{@certId})
453 * }
454 */
455
456 if (asn1_get_next(buf, len, &hdr) < 0 ||
457 hdr.class != ASN1_CLASS_UNIVERSAL ||
458 hdr.tag != ASN1_TAG_SEQUENCE) {
459 wpa_printf(MSG_DEBUG,
460 "PKCS #12: Expected SEQUENCE (CertBag) - found class %d tag 0x%x",
461 hdr.class, hdr.tag);
462 return -1;
463 }
464
465 pos = hdr.payload;
466 end = hdr.payload + hdr.length;
467
468 if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
469 wpa_printf(MSG_DEBUG,
470 "PKCS #12: Failed to parse OID (certId)");
471 return -1;
472 }
473
474 asn1_oid_to_str(&oid, obuf, sizeof(obuf));
475 wpa_printf(MSG_DEBUG, "PKCS #12: certId %s", obuf);
476
477 if (!is_oid_pkcs9_x509_cert(&oid)) {
478 wpa_printf(MSG_DEBUG,
479 "PKCS #12: Ignored unsupported certificate type (certId %s)",
480 obuf);
481 }
482
483 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
484 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
485 hdr.tag != 0) {
486 wpa_printf(MSG_DEBUG,
487 "PKCS #12: Expected [0] EXPLICIT (certValue) - found class %d tag 0x%x",
488 hdr.class, hdr.tag);
489 return -1;
490 }
491
492 if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
493 hdr.class != ASN1_CLASS_UNIVERSAL ||
494 hdr.tag != ASN1_TAG_OCTETSTRING) {
495 wpa_printf(MSG_DEBUG,
496 "PKCS #12: Expected OCTET STRING (x509Certificate) - found class %d tag 0x%x",
497 hdr.class, hdr.tag);
498 return -1;
499 }
500
501 wpa_hexdump(MSG_DEBUG, "PKCS #12: x509Certificate",
502 hdr.payload, hdr.length);
503 if (cred->cert) {
504 struct x509_certificate *cert;
505
506 wpa_printf(MSG_DEBUG, "PKCS #12: Ignore extra certificate");
507 cert = x509_certificate_parse(hdr.payload, hdr.length);
508 if (!cert) {
509 wpa_printf(MSG_DEBUG,
510 "PKCS #12: Failed to parse x509Certificate");
511 return 0;
512 }
513 x509_certificate_chain_free(cert);
514
515 return 0;
516 }
517 return tlsv1_set_cert(cred, NULL, hdr.payload, hdr.length);
518}
519
520
521static int pkcs12_parse_attr_friendly_name(const u8 *pos, const u8 *end)
522{
523 struct asn1_hdr hdr;
524
525 /*
526 * RFC 2985, 5.5.1:
527 * friendlyName ATTRIBUTE ::= {
528 * WITH SYNTAX BMPString (SIZE(1..pkcs-9-ub-friendlyName))
529 * EQUALITY MATCHING RULE caseIgnoreMatch
530 * SINGLE VALUE TRUE
531 * ID pkcs-9-at-friendlyName
532 * }
533 */
534 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
535 hdr.class != ASN1_CLASS_UNIVERSAL ||
536 hdr.tag != ASN1_TAG_BMPSTRING) {
537 wpa_printf(MSG_DEBUG,
538 "PKCS #12: Expected BMPSTRING (friendlyName) - found class %d tag 0x%x",
539 hdr.class, hdr.tag);
540 return 0;
541 }
542 wpa_hexdump_ascii(MSG_DEBUG, "PKCS #12: friendlyName",
543 hdr.payload, hdr.length);
544 return 0;
545}
546
547
548static int pkcs12_parse_attr_local_key_id(const u8 *pos, const u8 *end)
549{
550 struct asn1_hdr hdr;
551
552 /*
553 * RFC 2985, 5.5.2:
554 * localKeyId ATTRIBUTE ::= {
555 * WITH SYNTAX OCTET STRING
556 * EQUALITY MATCHING RULE octetStringMatch
557 * SINGLE VALUE TRUE
558 * ID pkcs-9-at-localKeyId
559 * }
560 */
561 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
562 hdr.class != ASN1_CLASS_UNIVERSAL ||
563 hdr.tag != ASN1_TAG_OCTETSTRING) {
564 wpa_printf(MSG_DEBUG,
565 "PKCS #12: Expected OCTET STRING (localKeyID) - found class %d tag 0x%x",
566 hdr.class, hdr.tag);
567 return -1;
568 }
569 wpa_hexdump_key(MSG_DEBUG, "PKCS #12: localKeyID",
570 hdr.payload, hdr.length);
571 return 0;
572}
573
574
575static int pkcs12_parse_attr(const u8 *pos, size_t len)
576{
577 const u8 *end = pos + len;
578 struct asn1_hdr hdr;
579 struct asn1_oid a_oid;
580 char obuf[80];
581
582 /*
583 * PKCS12Attribute ::= SEQUENCE {
584 * attrId ATTRIBUTE.&id ({PKCS12AttrSet}),
585 * attrValues SET OF ATTRIBUTE.&Type ({PKCS12AttrSet}{@attrId})
586 * }
587 */
588
589 if (asn1_get_oid(pos, end - pos, &a_oid, &pos)) {
590 wpa_printf(MSG_DEBUG, "PKCS #12: Failed to parse OID (attrId)");
591 return -1;
592 }
593
594 asn1_oid_to_str(&a_oid, obuf, sizeof(obuf));
595 wpa_printf(MSG_DEBUG, "PKCS #12: attrId %s", obuf);
596
597 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
598 hdr.class != ASN1_CLASS_UNIVERSAL ||
599 hdr.tag != ASN1_TAG_SET) {
600 wpa_printf(MSG_DEBUG,
601 "PKCS #12: Expected SET (attrValues) - found class %d tag 0x%x",
602 hdr.class, hdr.tag);
603 return -1;
604 }
605 wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: attrValues",
606 hdr.payload, hdr.length);
607 pos = hdr.payload;
608 end = hdr.payload + hdr.length;
609
610 if (is_oid_pkcs9_friendly_name(&a_oid))
611 return pkcs12_parse_attr_friendly_name(pos, end);
612 if (is_oid_pkcs9_local_key_id(&a_oid))
613 return pkcs12_parse_attr_local_key_id(pos, end);
614
615 wpa_printf(MSG_DEBUG, "PKCS #12: Ignore unknown attribute");
616 return 0;
617}
618
619
620static int pkcs12_safebag(struct tlsv1_credentials *cred,
621 const u8 *buf, size_t len, const char *passwd)
622{
623 struct asn1_hdr hdr;
624 struct asn1_oid oid;
625 char obuf[80];
626 const u8 *pos = buf, *end = buf + len;
627 const u8 *value;
628 size_t value_len;
629
630 wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: SafeBag", buf, len);
631
632 /* BAG-TYPE ::= TYPE-IDENTIFIER */
633 if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
634 wpa_printf(MSG_DEBUG,
635 "PKCS #12: Failed to parse OID (BAG-TYPE)");
636 return -1;
637 }
638
639 asn1_oid_to_str(&oid, obuf, sizeof(obuf));
640 wpa_printf(MSG_DEBUG, "PKCS #12: BAG-TYPE %s", obuf);
641
642 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
643 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
644 hdr.tag != 0) {
645 wpa_printf(MSG_DEBUG,
646 "PKCS #12: Expected [0] EXPLICIT (bagValue) - found class %d tag 0x%x",
647 hdr.class, hdr.tag);
648 return 0;
649 }
650 value = hdr.payload;
651 value_len = hdr.length;
652 wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: bagValue", value, value_len);
653 pos = hdr.payload + hdr.length;
654
655 if (pos < end) {
656 /* bagAttributes SET OF PKCS12Attribute OPTIONAL */
657 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
658 hdr.class != ASN1_CLASS_UNIVERSAL ||
659 hdr.tag != ASN1_TAG_SET) {
660 wpa_printf(MSG_DEBUG,
661 "PKCS #12: Expected SET (bagAttributes) - found class %d tag 0x%x",
662 hdr.class, hdr.tag);
663 return -1;
664 }
665 wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: bagAttributes",
666 hdr.payload, hdr.length);
667
668 pos = hdr.payload;
669 end = hdr.payload + hdr.length;
670 while (pos < end) {
671 /* PKCS12Attribute ::= SEQUENCE */
672 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
673 hdr.class != ASN1_CLASS_UNIVERSAL ||
674 hdr.tag != ASN1_TAG_SEQUENCE) {
675 wpa_printf(MSG_DEBUG,
676 "PKCS #12: Expected SEQUENCE (PKCS12Attribute) - found class %d tag 0x%x",
677 hdr.class, hdr.tag);
678 return -1;
679 }
680 if (pkcs12_parse_attr(hdr.payload, hdr.length) < 0)
681 return -1;
682 pos = hdr.payload + hdr.length;
683 }
684 }
685
686 if (pkcs12_is_bagtype_oid(&oid, 1))
687 return pkcs12_keybag(cred, value, value_len);
688 if (pkcs12_is_bagtype_oid(&oid, 2))
689 return pkcs12_pkcs8_keybag(cred, value, value_len, passwd);
690 if (pkcs12_is_bagtype_oid(&oid, 3))
691 return pkcs12_certbag(cred, value, value_len);
692
693 wpa_printf(MSG_DEBUG, "PKCS #12: Ignore unsupported BAG-TYPE");
694 return 0;
695}
696
697
698static int pkcs12_safecontents(struct tlsv1_credentials *cred,
699 const u8 *buf, size_t len,
700 const char *passwd)
701{
702 struct asn1_hdr hdr;
703 const u8 *pos, *end;
704
705 /* SafeContents ::= SEQUENCE OF SafeBag */
706 if (asn1_get_next(buf, len, &hdr) < 0 ||
707 hdr.class != ASN1_CLASS_UNIVERSAL ||
708 hdr.tag != ASN1_TAG_SEQUENCE) {
709 wpa_printf(MSG_DEBUG,
710 "PKCS #12: Expected SEQUENCE (SafeContents) - found class %d tag 0x%x",
711 hdr.class, hdr.tag);
712 return -1;
713 }
714 pos = hdr.payload;
715 end = hdr.payload + hdr.length;
716
717 /*
718 * SafeBag ::= SEQUENCE {
719 * bagId BAG-TYPE.&id ({PKCS12BagSet})
720 * bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}),
721 * bagAttributes SET OF PKCS12Attribute OPTIONAL
722 * }
723 */
724
725 while (pos < end) {
726 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
727 hdr.class != ASN1_CLASS_UNIVERSAL ||
728 hdr.tag != ASN1_TAG_SEQUENCE) {
729 wpa_printf(MSG_DEBUG,
730 "PKCS #12: Expected SEQUENCE (SafeBag) - found class %d tag 0x%x",
731 hdr.class, hdr.tag);
732 return -1;
733 }
734 if (pkcs12_safebag(cred, hdr.payload, hdr.length, passwd) < 0)
735 return -1;
736 pos = hdr.payload + hdr.length;
737 }
738
739 return 0;
740}
741
742
743static int pkcs12_parse_content_data(struct tlsv1_credentials *cred,
744 const u8 *pos, const u8 *end,
745 const char *passwd)
746{
747 struct asn1_hdr hdr;
748
749 /* Data ::= OCTET STRING */
750 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
751 hdr.class != ASN1_CLASS_UNIVERSAL ||
752 hdr.tag != ASN1_TAG_OCTETSTRING) {
753 wpa_printf(MSG_DEBUG,
754 "PKCS #12: Expected OCTET STRING (Data) - found class %d tag 0x%x",
755 hdr.class, hdr.tag);
756 return -1;
757 }
758
759 wpa_hexdump(MSG_MSGDUMP, "PKCS #12: Data", hdr.payload, hdr.length);
760
761 return pkcs12_safecontents(cred, hdr.payload, hdr.length, passwd);
762}
763
764
765static int pkcs12_parse_content_enc_data(struct tlsv1_credentials *cred,
766 const u8 *pos, const u8 *end,
767 const char *passwd)
768{
769 struct asn1_hdr hdr;
770 struct asn1_oid oid;
771 char buf[80];
772 const u8 *enc_alg;
773 u8 *data;
774 size_t enc_alg_len, data_len;
775 int res = -1;
776
777 /*
778 * EncryptedData ::= SEQUENCE {
779 * version Version,
780 * encryptedContentInfo EncryptedContentInfo }
781 */
782 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
783 hdr.class != ASN1_CLASS_UNIVERSAL ||
784 hdr.tag != ASN1_TAG_SEQUENCE) {
785 wpa_printf(MSG_DEBUG,
786 "PKCS #12: Expected SEQUENCE (EncryptedData) - found class %d tag 0x%x",
787 hdr.class, hdr.tag);
788 return 0;
789 }
790 pos = hdr.payload;
791
792 /* Version ::= INTEGER */
793 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
794 hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
795 wpa_printf(MSG_DEBUG,
796 "PKCS #12: No INTEGER tag found for version; class=%d tag=0x%x",
797 hdr.class, hdr.tag);
798 return -1;
799 }
800 if (hdr.length != 1 || hdr.payload[0] != 0) {
801 wpa_printf(MSG_DEBUG, "PKCS #12: Unrecognized PKCS #7 version");
802 return -1;
803 }
804 pos = hdr.payload + hdr.length;
805
806 wpa_hexdump(MSG_MSGDUMP, "PKCS #12: EncryptedContentInfo",
807 pos, end - pos);
808
809 /*
810 * EncryptedContentInfo ::= SEQUENCE {
811 * contentType ContentType,
812 * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
813 * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL }
814 */
815 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
816 hdr.class != ASN1_CLASS_UNIVERSAL ||
817 hdr.tag != ASN1_TAG_SEQUENCE) {
818 wpa_printf(MSG_DEBUG,
819 "PKCS #12: Expected SEQUENCE (EncryptedContentInfo) - found class %d tag 0x%x",
820 hdr.class, hdr.tag);
821 return -1;
822 }
823
824 pos = hdr.payload;
825 end = pos + hdr.length;
826
827 /* ContentType ::= OBJECT IDENTIFIER */
828 if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
829 wpa_printf(MSG_DEBUG,
830 "PKCS #12: Could not find OBJECT IDENTIFIER (contentType)");
831 return -1;
832 }
833 asn1_oid_to_str(&oid, buf, sizeof(buf));
834 wpa_printf(MSG_DEBUG, "PKCS #12: EncryptedContentInfo::contentType %s",
835 buf);
836
837 if (!is_oid_pkcs7_data(&oid)) {
838 wpa_printf(MSG_DEBUG,
839 "PKCS #12: Unsupported EncryptedContentInfo::contentType %s",
840 buf);
841 return 0;
842 }
843
844 /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
845 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
846 hdr.class != ASN1_CLASS_UNIVERSAL ||
847 hdr.tag != ASN1_TAG_SEQUENCE) {
848 wpa_printf(MSG_DEBUG, "PKCS #12: Expected SEQUENCE (ContentEncryptionAlgorithmIdentifier) - found class %d tag 0x%x",
849 hdr.class, hdr.tag);
850 return -1;
851 }
852 enc_alg = hdr.payload;
853 enc_alg_len = hdr.length;
854 pos = hdr.payload + hdr.length;
855
856 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
857 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
858 hdr.tag != 0) {
859 wpa_printf(MSG_DEBUG,
860 "PKCS #12: Expected [0] IMPLICIT (encryptedContent) - found class %d tag 0x%x",
861 hdr.class, hdr.tag);
862 return -1;
863 }
864
865 /* EncryptedContent ::= OCTET STRING */
866 data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length,
867 passwd, &data_len);
868 if (data) {
869 wpa_hexdump_key(MSG_MSGDUMP,
870 "PKCS #12: Decrypted encryptedContent",
871 data, data_len);
872 res = pkcs12_safecontents(cred, data, data_len, passwd);
873 os_free(data);
874 }
875
876 return res;
877}
878
879
880static int pkcs12_parse_content(struct tlsv1_credentials *cred,
881 const u8 *buf, size_t len,
882 const char *passwd)
883{
884 const u8 *pos = buf;
885 const u8 *end = buf + len;
886 struct asn1_oid oid;
887 char txt[80];
888 struct asn1_hdr hdr;
889
890 wpa_hexdump(MSG_MSGDUMP, "PKCS #12: ContentInfo", buf, len);
891
892 if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
893 wpa_printf(MSG_DEBUG,
894 "PKCS #12: Could not find OBJECT IDENTIFIER (contentType)");
895 return 0;
896 }
897
898 asn1_oid_to_str(&oid, txt, sizeof(txt));
899 wpa_printf(MSG_DEBUG, "PKCS #12: contentType %s", txt);
900
901 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
902 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
903 hdr.tag != 0) {
904 wpa_printf(MSG_DEBUG,
905 "PKCS #12: Expected [0] EXPLICIT (content) - found class %d tag 0x%x",
906 hdr.class, hdr.tag);
907 return 0;
908 }
909 pos = hdr.payload;
910
911 if (is_oid_pkcs7_data(&oid))
912 return pkcs12_parse_content_data(cred, pos, end, passwd);
913 if (is_oid_pkcs7_enc_data(&oid))
914 return pkcs12_parse_content_enc_data(cred, pos, end, passwd);
915
916 wpa_printf(MSG_DEBUG, "PKCS #12: Ignored unsupported contentType %s",
917 txt);
918
919 return 0;
920}
921
922
923static int pkcs12_parse(struct tlsv1_credentials *cred,
924 const u8 *key, size_t len, const char *passwd)
925{
926 struct asn1_hdr hdr;
927 const u8 *pos, *end;
928 struct asn1_oid oid;
929 char buf[80];
930
931 /*
932 * PFX ::= SEQUENCE {
933 * version INTEGER {v3(3)}(v3,...),
934 * authSafe ContentInfo,
935 * macData MacData OPTIONAL
936 * }
937 */
938
939 if (asn1_get_next(key, len, &hdr) < 0 ||
940 hdr.class != ASN1_CLASS_UNIVERSAL ||
941 hdr.tag != ASN1_TAG_SEQUENCE) {
942 wpa_printf(MSG_DEBUG,
943 "PKCS #12: Expected SEQUENCE (PFX) - found class %d tag 0x%x; assume PKCS #12 not used",
944 hdr.class, hdr.tag);
945 return -1;
946 }
947
948 pos = hdr.payload;
949 end = pos + hdr.length;
950
951 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
952 hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
953 wpa_printf(MSG_DEBUG,
954 "PKCS #12: No INTEGER tag found for version; class=%d tag=0x%x",
955 hdr.class, hdr.tag);
956 return -1;
957 }
958 if (hdr.length != 1 || hdr.payload[0] != 3) {
959 wpa_printf(MSG_DEBUG, "PKCS #12: Unrecognized version");
960 return -1;
961 }
962 pos = hdr.payload + hdr.length;
963
964 /*
965 * ContentInfo ::= SEQUENCE {
966 * contentType ContentType,
967 * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
968 */
969
970 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
971 hdr.class != ASN1_CLASS_UNIVERSAL ||
972 hdr.tag != ASN1_TAG_SEQUENCE) {
973 wpa_printf(MSG_DEBUG,
974 "PKCS #12: Expected SEQUENCE (authSafe) - found class %d tag 0x%x; assume PKCS #12 not used",
975 hdr.class, hdr.tag);
976 return -1;
977 }
978
979 pos = hdr.payload;
980 end = pos + hdr.length;
981
982 /* ContentType ::= OBJECT IDENTIFIER */
983 if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
984 wpa_printf(MSG_DEBUG,
985 "PKCS #12: Could not find OBJECT IDENTIFIER (contentType); assume PKCS #12 not used");
986 return -1;
987 }
988 asn1_oid_to_str(&oid, buf, sizeof(buf));
989 wpa_printf(MSG_DEBUG, "PKCS #12: contentType %s", buf);
990 if (!is_oid_pkcs7_data(&oid)) {
991 wpa_printf(MSG_DEBUG, "PKCS #12: Unsupported contentType %s",
992 buf);
993 return -1;
994 }
995
996 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
997 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
998 hdr.tag != 0) {
999 wpa_printf(MSG_DEBUG,
1000 "PKCS #12: Expected [0] EXPLICIT (content) - found class %d tag 0x%x; assume PKCS #12 not used",
1001 hdr.class, hdr.tag);
1002 return -1;
1003 }
1004
1005 pos = hdr.payload;
1006
1007 /* Data ::= OCTET STRING */
1008 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1009 hdr.class != ASN1_CLASS_UNIVERSAL ||
1010 hdr.tag != ASN1_TAG_OCTETSTRING) {
1011 wpa_printf(MSG_DEBUG,
1012 "PKCS #12: Expected OCTET STRING (Data) - found class %d tag 0x%x; assume PKCS #12 not used",
1013 hdr.class, hdr.tag);
1014 return -1;
1015 }
1016
1017 /*
1018 * AuthenticatedSafe ::= SEQUENCE OF ContentInfo
1019 * -- Data if unencrypted
1020 * -- EncryptedData if password-encrypted
1021 * -- EnvelopedData if public key-encrypted
1022 */
1023 wpa_hexdump(MSG_MSGDUMP, "PKCS #12: Data content",
1024 hdr.payload, hdr.length);
1025
1026 if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
1027 hdr.class != ASN1_CLASS_UNIVERSAL ||
1028 hdr.tag != ASN1_TAG_SEQUENCE) {
1029 wpa_printf(MSG_DEBUG,
1030 "PKCS #12: Expected SEQUENCE within Data content - found class %d tag 0x%x; assume PKCS #12 not used",
1031 hdr.class, hdr.tag);
1032 return -1;
1033 }
1034
1035 pos = hdr.payload;
1036 end = pos + hdr.length;
1037
1038 while (end > pos) {
1039 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1040 hdr.class != ASN1_CLASS_UNIVERSAL ||
1041 hdr.tag != ASN1_TAG_SEQUENCE) {
1042 wpa_printf(MSG_DEBUG,
1043 "PKCS #12: Expected SEQUENCE (ContentInfo) - found class %d tag 0x%x; assume PKCS #12 not used",
1044 hdr.class, hdr.tag);
1045 return -1;
1046 }
1047 if (pkcs12_parse_content(cred, hdr.payload, hdr.length,
1048 passwd) < 0)
1049 return -1;
1050
1051 pos = hdr.payload + hdr.length;
1052 }
1053
1054 return 0;
1055}
1056
1057#endif /* PKCS12_FUNCS */
1058
1059
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001060static int tlsv1_set_key(struct tlsv1_credentials *cred,
1061 const u8 *key, size_t len, const char *passwd)
1062{
1063 cred->key = crypto_private_key_import(key, len, passwd);
1064 if (cred->key == NULL)
1065 cred->key = tlsv1_set_key_pem(key, len);
1066 if (cred->key == NULL)
1067 cred->key = tlsv1_set_key_enc_pem(key, len, passwd);
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08001068#ifdef PKCS12_FUNCS
1069 if (!cred->key)
1070 pkcs12_parse(cred, key, len, passwd);
1071#endif /* PKCS12_FUNCS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001072 if (cred->key == NULL) {
1073 wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
1074 return -1;
1075 }
1076 return 0;
1077}
1078
1079
1080/**
1081 * tlsv1_set_private_key - Set private key
1082 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
1083 * @private_key: File or reference name for the key in PEM or DER format
1084 * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
1085 * passphrase is used.
1086 * @private_key_blob: private_key as inlined data or %NULL if not used
1087 * @private_key_blob_len: private_key_blob length
1088 * Returns: 0 on success, -1 on failure
1089 */
1090int tlsv1_set_private_key(struct tlsv1_credentials *cred,
1091 const char *private_key,
1092 const char *private_key_passwd,
1093 const u8 *private_key_blob,
1094 size_t private_key_blob_len)
1095{
1096 crypto_private_key_free(cred->key);
1097 cred->key = NULL;
1098
1099 if (private_key_blob)
1100 return tlsv1_set_key(cred, private_key_blob,
1101 private_key_blob_len,
1102 private_key_passwd);
1103
1104 if (private_key) {
1105 u8 *buf;
1106 size_t len;
1107 int ret;
1108
1109 buf = (u8 *) os_readfile(private_key, &len);
1110 if (buf == NULL) {
1111 wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
1112 private_key);
1113 return -1;
1114 }
1115
1116 ret = tlsv1_set_key(cred, buf, len, private_key_passwd);
1117 os_free(buf);
1118 return ret;
1119 }
1120
1121 return 0;
1122}
1123
1124
1125static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
1126 const u8 *dh, size_t len)
1127{
1128 struct asn1_hdr hdr;
1129 const u8 *pos, *end;
1130
1131 pos = dh;
1132 end = dh + len;
1133
1134 /*
1135 * DHParameter ::= SEQUENCE {
1136 * prime INTEGER, -- p
1137 * base INTEGER, -- g
1138 * privateValueLength INTEGER OPTIONAL }
1139 */
1140
1141 /* DHParamer ::= SEQUENCE */
1142 if (asn1_get_next(pos, len, &hdr) < 0 ||
1143 hdr.class != ASN1_CLASS_UNIVERSAL ||
1144 hdr.tag != ASN1_TAG_SEQUENCE) {
1145 wpa_printf(MSG_DEBUG, "DH: DH parameters did not start with a "
1146 "valid SEQUENCE - found class %d tag 0x%x",
1147 hdr.class, hdr.tag);
1148 return -1;
1149 }
1150 pos = hdr.payload;
1151
1152 /* prime INTEGER */
1153 if (asn1_get_next(pos, end - pos, &hdr) < 0)
1154 return -1;
1155
1156 if (hdr.class != ASN1_CLASS_UNIVERSAL ||
1157 hdr.tag != ASN1_TAG_INTEGER) {
1158 wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for p; "
1159 "class=%d tag=0x%x", hdr.class, hdr.tag);
1160 return -1;
1161 }
1162
1163 wpa_hexdump(MSG_MSGDUMP, "DH: prime (p)", hdr.payload, hdr.length);
1164 if (hdr.length == 0)
1165 return -1;
1166 os_free(cred->dh_p);
1167 cred->dh_p = os_malloc(hdr.length);
1168 if (cred->dh_p == NULL)
1169 return -1;
1170 os_memcpy(cred->dh_p, hdr.payload, hdr.length);
1171 cred->dh_p_len = hdr.length;
1172 pos = hdr.payload + hdr.length;
1173
1174 /* base INTEGER */
1175 if (asn1_get_next(pos, end - pos, &hdr) < 0)
1176 return -1;
1177
1178 if (hdr.class != ASN1_CLASS_UNIVERSAL ||
1179 hdr.tag != ASN1_TAG_INTEGER) {
1180 wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for g; "
1181 "class=%d tag=0x%x", hdr.class, hdr.tag);
1182 return -1;
1183 }
1184
1185 wpa_hexdump(MSG_MSGDUMP, "DH: base (g)", hdr.payload, hdr.length);
1186 if (hdr.length == 0)
1187 return -1;
1188 os_free(cred->dh_g);
1189 cred->dh_g = os_malloc(hdr.length);
1190 if (cred->dh_g == NULL)
1191 return -1;
1192 os_memcpy(cred->dh_g, hdr.payload, hdr.length);
1193 cred->dh_g_len = hdr.length;
1194
1195 return 0;
1196}
1197
1198
1199static const char *pem_dhparams_begin = "-----BEGIN DH PARAMETERS-----";
1200static const char *pem_dhparams_end = "-----END DH PARAMETERS-----";
1201
1202
1203static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred,
1204 const u8 *buf, size_t len)
1205{
1206 const u8 *pos, *end;
1207 unsigned char *der;
1208 size_t der_len;
1209
1210 pos = search_tag(pem_dhparams_begin, buf, len);
1211 if (!pos) {
1212 wpa_printf(MSG_DEBUG, "TLSv1: No PEM dhparams tag found - "
1213 "assume DER format");
1214 return tlsv1_set_dhparams_der(cred, buf, len);
1215 }
1216
1217 wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format dhparams into DER "
1218 "format");
1219
1220 pos += os_strlen(pem_dhparams_begin);
1221 end = search_tag(pem_dhparams_end, pos, buf + len - pos);
1222 if (end == NULL) {
1223 wpa_printf(MSG_INFO, "TLSv1: Could not find PEM dhparams end "
1224 "tag (%s)", pem_dhparams_end);
1225 return -1;
1226 }
1227
1228 der = base64_decode(pos, end - pos, &der_len);
1229 if (der == NULL) {
1230 wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams");
1231 return -1;
1232 }
1233
1234 if (tlsv1_set_dhparams_der(cred, der, der_len) < 0) {
1235 wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM dhparams "
1236 "DER conversion");
1237 os_free(der);
1238 return -1;
1239 }
1240
1241 os_free(der);
1242
1243 return 0;
1244}
1245
1246
1247/**
1248 * tlsv1_set_dhparams - Set Diffie-Hellman parameters
1249 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
1250 * @dh_file: File or reference name for the DH params in PEM or DER format
1251 * @dh_blob: DH params as inlined data or %NULL if not used
1252 * @dh_blob_len: dh_blob length
1253 * Returns: 0 on success, -1 on failure
1254 */
1255int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,
1256 const u8 *dh_blob, size_t dh_blob_len)
1257{
1258 if (dh_blob)
1259 return tlsv1_set_dhparams_blob(cred, dh_blob, dh_blob_len);
1260
1261 if (dh_file) {
1262 u8 *buf;
1263 size_t len;
1264 int ret;
1265
1266 buf = (u8 *) os_readfile(dh_file, &len);
1267 if (buf == NULL) {
1268 wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
1269 dh_file);
1270 return -1;
1271 }
1272
1273 ret = tlsv1_set_dhparams_blob(cred, buf, len);
1274 os_free(buf);
1275 return ret;
1276 }
1277
1278 return 0;
1279}