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