blob: 1310f4e10e8e607326d732fa8c35539c038a67c9 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * TLSv1 credentials
Dmitry Shmidt1b467752015-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 Shmidt1b467752015-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);
Dmitry Shmidtd97138d2015-12-28 13:27:49 -080039 os_free(cred->ocsp_stapling_response);
40 os_free(cred->ocsp_stapling_response_multi);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070041 os_free(cred);
42}
43
44
45static int tlsv1_add_cert_der(struct x509_certificate **chain,
46 const u8 *buf, size_t len)
47{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080048 struct x509_certificate *cert, *p;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070049 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
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080058 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 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070072
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-----";
82static const char *pem_key_begin = "-----BEGIN RSA PRIVATE KEY-----";
83static const char *pem_key_end = "-----END RSA PRIVATE KEY-----";
84static const char *pem_key2_begin = "-----BEGIN PRIVATE KEY-----";
85static const char *pem_key2_end = "-----END PRIVATE KEY-----";
86static const char *pem_key_enc_begin = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
87static const char *pem_key_enc_end = "-----END ENCRYPTED PRIVATE KEY-----";
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
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800133 der = base64_decode((const char *) pos, end - pos, &der_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700134 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{
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -0800198 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
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
233 cred->ca_cert_verify = cert || cert_blob || path;
234
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700235 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
266static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len)
267{
268 const u8 *pos, *end;
269 unsigned char *der;
270 size_t der_len;
271 struct crypto_private_key *pkey;
272
273 pos = search_tag(pem_key_begin, key, len);
274 if (!pos) {
275 pos = search_tag(pem_key2_begin, key, len);
276 if (!pos)
277 return NULL;
278 pos += os_strlen(pem_key2_begin);
279 end = search_tag(pem_key2_end, pos, key + len - pos);
280 if (!end)
281 return NULL;
282 } else {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800283 const u8 *pos2;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700284 pos += os_strlen(pem_key_begin);
285 end = search_tag(pem_key_end, pos, key + len - pos);
286 if (!end)
287 return NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800288 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 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700294 }
295
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800296 der = base64_decode((const char *) pos, end - pos, &der_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700297 if (!der)
298 return NULL;
299 pkey = crypto_private_key_import(der, der_len, NULL);
300 os_free(der);
301 return pkey;
302}
303
304
305static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key,
306 size_t len,
307 const char *passwd)
308{
309 const u8 *pos, *end;
310 unsigned char *der;
311 size_t der_len;
312 struct crypto_private_key *pkey;
313
314 if (passwd == NULL)
315 return NULL;
316 pos = search_tag(pem_key_enc_begin, key, len);
317 if (!pos)
318 return NULL;
319 pos += os_strlen(pem_key_enc_begin);
320 end = search_tag(pem_key_enc_end, pos, key + len - pos);
321 if (!end)
322 return NULL;
323
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800324 der = base64_decode((const char *) pos, end - pos, &der_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700325 if (!der)
326 return NULL;
327 pkey = crypto_private_key_import(der, der_len, passwd);
328 os_free(der);
329 return pkey;
330}
331
332
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800333#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
Hai Shalomc1a21442022-02-04 13:43:00 -0800458 if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
459 asn1_unexpected(&hdr, "PKCS #12: Expected SEQUENCE (CertBag)");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800460 return -1;
461 }
462
463 pos = hdr.payload;
464 end = hdr.payload + hdr.length;
465
466 if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
467 wpa_printf(MSG_DEBUG,
468 "PKCS #12: Failed to parse OID (certId)");
469 return -1;
470 }
471
472 asn1_oid_to_str(&oid, obuf, sizeof(obuf));
473 wpa_printf(MSG_DEBUG, "PKCS #12: certId %s", obuf);
474
475 if (!is_oid_pkcs9_x509_cert(&oid)) {
476 wpa_printf(MSG_DEBUG,
477 "PKCS #12: Ignored unsupported certificate type (certId %s)",
478 obuf);
479 }
480
Hai Shalomc1a21442022-02-04 13:43:00 -0800481 if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed ||
482 !asn1_is_cs_tag(&hdr, 0)) {
483 asn1_unexpected(&hdr,
484 "PKCS #12: Expected [0] EXPLICIT (certValue)");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800485 return -1;
486 }
487
488 if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
Hai Shalomc1a21442022-02-04 13:43:00 -0800489 !asn1_is_octetstring(&hdr)) {
490 asn1_unexpected(&hdr,
491 "PKCS #12: Expected OCTET STRING (x509Certificate)");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800492 return -1;
493 }
494
495 wpa_hexdump(MSG_DEBUG, "PKCS #12: x509Certificate",
496 hdr.payload, hdr.length);
497 if (cred->cert) {
498 struct x509_certificate *cert;
499
500 wpa_printf(MSG_DEBUG, "PKCS #12: Ignore extra certificate");
501 cert = x509_certificate_parse(hdr.payload, hdr.length);
502 if (!cert) {
503 wpa_printf(MSG_DEBUG,
504 "PKCS #12: Failed to parse x509Certificate");
505 return 0;
506 }
507 x509_certificate_chain_free(cert);
508
509 return 0;
510 }
511 return tlsv1_set_cert(cred, NULL, hdr.payload, hdr.length);
512}
513
514
515static int pkcs12_parse_attr_friendly_name(const u8 *pos, const u8 *end)
516{
517 struct asn1_hdr hdr;
518
519 /*
520 * RFC 2985, 5.5.1:
521 * friendlyName ATTRIBUTE ::= {
522 * WITH SYNTAX BMPString (SIZE(1..pkcs-9-ub-friendlyName))
523 * EQUALITY MATCHING RULE caseIgnoreMatch
524 * SINGLE VALUE TRUE
525 * ID pkcs-9-at-friendlyName
526 * }
527 */
528 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
Hai Shalomc1a21442022-02-04 13:43:00 -0800529 !asn1_is_bmpstring(&hdr)) {
530 asn1_unexpected(&hdr,
531 "PKCS #12: Expected BMPSTRING (friendlyName)");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800532 return 0;
533 }
534 wpa_hexdump_ascii(MSG_DEBUG, "PKCS #12: friendlyName",
535 hdr.payload, hdr.length);
536 return 0;
537}
538
539
540static int pkcs12_parse_attr_local_key_id(const u8 *pos, const u8 *end)
541{
542 struct asn1_hdr hdr;
543
544 /*
545 * RFC 2985, 5.5.2:
546 * localKeyId ATTRIBUTE ::= {
547 * WITH SYNTAX OCTET STRING
548 * EQUALITY MATCHING RULE octetStringMatch
549 * SINGLE VALUE TRUE
550 * ID pkcs-9-at-localKeyId
551 * }
552 */
553 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
Hai Shalomc1a21442022-02-04 13:43:00 -0800554 !asn1_is_octetstring(&hdr)) {
555 asn1_unexpected(&hdr,
556 "PKCS #12: Expected OCTET STRING (localKeyID)");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800557 return -1;
558 }
559 wpa_hexdump_key(MSG_DEBUG, "PKCS #12: localKeyID",
560 hdr.payload, hdr.length);
561 return 0;
562}
563
564
565static int pkcs12_parse_attr(const u8 *pos, size_t len)
566{
567 const u8 *end = pos + len;
568 struct asn1_hdr hdr;
569 struct asn1_oid a_oid;
570 char obuf[80];
571
572 /*
573 * PKCS12Attribute ::= SEQUENCE {
574 * attrId ATTRIBUTE.&id ({PKCS12AttrSet}),
575 * attrValues SET OF ATTRIBUTE.&Type ({PKCS12AttrSet}{@attrId})
576 * }
577 */
578
579 if (asn1_get_oid(pos, end - pos, &a_oid, &pos)) {
580 wpa_printf(MSG_DEBUG, "PKCS #12: Failed to parse OID (attrId)");
581 return -1;
582 }
583
584 asn1_oid_to_str(&a_oid, obuf, sizeof(obuf));
585 wpa_printf(MSG_DEBUG, "PKCS #12: attrId %s", obuf);
586
Hai Shalomc1a21442022-02-04 13:43:00 -0800587 if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_set(&hdr)) {
588 asn1_unexpected(&hdr, "PKCS #12: Expected SET (attrValues)");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800589 return -1;
590 }
591 wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: attrValues",
592 hdr.payload, hdr.length);
593 pos = hdr.payload;
594 end = hdr.payload + hdr.length;
595
596 if (is_oid_pkcs9_friendly_name(&a_oid))
597 return pkcs12_parse_attr_friendly_name(pos, end);
598 if (is_oid_pkcs9_local_key_id(&a_oid))
599 return pkcs12_parse_attr_local_key_id(pos, end);
600
601 wpa_printf(MSG_DEBUG, "PKCS #12: Ignore unknown attribute");
602 return 0;
603}
604
605
606static int pkcs12_safebag(struct tlsv1_credentials *cred,
607 const u8 *buf, size_t len, const char *passwd)
608{
609 struct asn1_hdr hdr;
610 struct asn1_oid oid;
611 char obuf[80];
612 const u8 *pos = buf, *end = buf + len;
613 const u8 *value;
614 size_t value_len;
615
616 wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: SafeBag", buf, len);
617
618 /* BAG-TYPE ::= TYPE-IDENTIFIER */
619 if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
620 wpa_printf(MSG_DEBUG,
621 "PKCS #12: Failed to parse OID (BAG-TYPE)");
622 return -1;
623 }
624
625 asn1_oid_to_str(&oid, obuf, sizeof(obuf));
626 wpa_printf(MSG_DEBUG, "PKCS #12: BAG-TYPE %s", obuf);
627
Hai Shalomc1a21442022-02-04 13:43:00 -0800628 if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed ||
629 !asn1_is_cs_tag(&hdr, 0)) {
630 asn1_unexpected(&hdr,
631 "PKCS #12: Expected [0] EXPLICIT (bagValue)");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800632 return 0;
633 }
634 value = hdr.payload;
635 value_len = hdr.length;
636 wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: bagValue", value, value_len);
637 pos = hdr.payload + hdr.length;
638
639 if (pos < end) {
640 /* bagAttributes SET OF PKCS12Attribute OPTIONAL */
641 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
Hai Shalomc1a21442022-02-04 13:43:00 -0800642 !asn1_is_set(&hdr)) {
643 asn1_unexpected(&hdr,
644 "PKCS #12: Expected SET (bagAttributes)");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800645 return -1;
646 }
647 wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: bagAttributes",
648 hdr.payload, hdr.length);
649
650 pos = hdr.payload;
651 end = hdr.payload + hdr.length;
652 while (pos < end) {
653 /* PKCS12Attribute ::= SEQUENCE */
654 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
Hai Shalomc1a21442022-02-04 13:43:00 -0800655 !asn1_is_sequence(&hdr)) {
656 asn1_unexpected(&hdr,
657 "PKCS #12: Expected SEQUENCE (PKCS12Attribute)");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800658 return -1;
659 }
660 if (pkcs12_parse_attr(hdr.payload, hdr.length) < 0)
661 return -1;
662 pos = hdr.payload + hdr.length;
663 }
664 }
665
666 if (pkcs12_is_bagtype_oid(&oid, 1))
667 return pkcs12_keybag(cred, value, value_len);
668 if (pkcs12_is_bagtype_oid(&oid, 2))
669 return pkcs12_pkcs8_keybag(cred, value, value_len, passwd);
670 if (pkcs12_is_bagtype_oid(&oid, 3))
671 return pkcs12_certbag(cred, value, value_len);
672
673 wpa_printf(MSG_DEBUG, "PKCS #12: Ignore unsupported BAG-TYPE");
674 return 0;
675}
676
677
678static int pkcs12_safecontents(struct tlsv1_credentials *cred,
679 const u8 *buf, size_t len,
680 const char *passwd)
681{
682 struct asn1_hdr hdr;
683 const u8 *pos, *end;
684
685 /* SafeContents ::= SEQUENCE OF SafeBag */
Hai Shalomc1a21442022-02-04 13:43:00 -0800686 if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
687 asn1_unexpected(&hdr,
688 "PKCS #12: Expected SEQUENCE (SafeContents)");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800689 return -1;
690 }
691 pos = hdr.payload;
692 end = hdr.payload + hdr.length;
693
694 /*
695 * SafeBag ::= SEQUENCE {
696 * bagId BAG-TYPE.&id ({PKCS12BagSet})
697 * bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}),
698 * bagAttributes SET OF PKCS12Attribute OPTIONAL
699 * }
700 */
701
702 while (pos < end) {
703 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
Hai Shalomc1a21442022-02-04 13:43:00 -0800704 !asn1_is_sequence(&hdr)) {
705 asn1_unexpected(&hdr,
706 "PKCS #12: Expected SEQUENCE (SafeBag)");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800707 return -1;
708 }
709 if (pkcs12_safebag(cred, hdr.payload, hdr.length, passwd) < 0)
710 return -1;
711 pos = hdr.payload + hdr.length;
712 }
713
714 return 0;
715}
716
717
718static int pkcs12_parse_content_data(struct tlsv1_credentials *cred,
719 const u8 *pos, const u8 *end,
720 const char *passwd)
721{
722 struct asn1_hdr hdr;
723
724 /* Data ::= OCTET STRING */
725 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
Hai Shalomc1a21442022-02-04 13:43:00 -0800726 !asn1_is_octetstring(&hdr)) {
727 asn1_unexpected(&hdr, "PKCS #12: Expected OCTET STRING (Data)");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800728 return -1;
729 }
730
731 wpa_hexdump(MSG_MSGDUMP, "PKCS #12: Data", hdr.payload, hdr.length);
732
733 return pkcs12_safecontents(cred, hdr.payload, hdr.length, passwd);
734}
735
736
737static int pkcs12_parse_content_enc_data(struct tlsv1_credentials *cred,
738 const u8 *pos, const u8 *end,
739 const char *passwd)
740{
741 struct asn1_hdr hdr;
742 struct asn1_oid oid;
743 char buf[80];
744 const u8 *enc_alg;
745 u8 *data;
746 size_t enc_alg_len, data_len;
747 int res = -1;
748
749 /*
750 * EncryptedData ::= SEQUENCE {
751 * version Version,
752 * encryptedContentInfo EncryptedContentInfo }
753 */
754 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
Hai Shalomc1a21442022-02-04 13:43:00 -0800755 !asn1_is_sequence(&hdr)) {
756 asn1_unexpected(&hdr,
757 "PKCS #12: Expected SEQUENCE (EncryptedData)");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800758 return 0;
759 }
760 pos = hdr.payload;
761
762 /* Version ::= INTEGER */
Hai Shalomc1a21442022-02-04 13:43:00 -0800763 if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_integer(&hdr)) {
764 asn1_unexpected(&hdr,
765 "PKCS #12: No INTEGER tag found for version");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800766 return -1;
767 }
768 if (hdr.length != 1 || hdr.payload[0] != 0) {
769 wpa_printf(MSG_DEBUG, "PKCS #12: Unrecognized PKCS #7 version");
770 return -1;
771 }
772 pos = hdr.payload + hdr.length;
773
774 wpa_hexdump(MSG_MSGDUMP, "PKCS #12: EncryptedContentInfo",
775 pos, end - pos);
776
777 /*
778 * EncryptedContentInfo ::= SEQUENCE {
779 * contentType ContentType,
780 * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
781 * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL }
782 */
783 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
Hai Shalomc1a21442022-02-04 13:43:00 -0800784 !asn1_is_sequence(&hdr)) {
785 asn1_unexpected(&hdr,
786 "PKCS #12: Expected SEQUENCE (EncryptedContentInfo)");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800787 return -1;
788 }
789
790 pos = hdr.payload;
791 end = pos + hdr.length;
792
793 /* ContentType ::= OBJECT IDENTIFIER */
794 if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
795 wpa_printf(MSG_DEBUG,
796 "PKCS #12: Could not find OBJECT IDENTIFIER (contentType)");
797 return -1;
798 }
799 asn1_oid_to_str(&oid, buf, sizeof(buf));
800 wpa_printf(MSG_DEBUG, "PKCS #12: EncryptedContentInfo::contentType %s",
801 buf);
802
803 if (!is_oid_pkcs7_data(&oid)) {
804 wpa_printf(MSG_DEBUG,
805 "PKCS #12: Unsupported EncryptedContentInfo::contentType %s",
806 buf);
807 return 0;
808 }
809
810 /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
811 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
Hai Shalomc1a21442022-02-04 13:43:00 -0800812 !asn1_is_sequence(&hdr)) {
813 asn1_unexpected(&hdr,
814 "PKCS #12: Expected SEQUENCE (ContentEncryptionAlgorithmIdentifier)");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800815 return -1;
816 }
817 enc_alg = hdr.payload;
818 enc_alg_len = hdr.length;
819 pos = hdr.payload + hdr.length;
820
Hai Shalomc1a21442022-02-04 13:43:00 -0800821 if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.constructed ||
822 !asn1_is_cs_tag(&hdr, 0)) {
823 asn1_unexpected(&hdr,
824 "PKCS #12: Expected [0] IMPLICIT (encryptedContent)");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800825 return -1;
826 }
827
828 /* EncryptedContent ::= OCTET STRING */
829 data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length,
830 passwd, &data_len);
831 if (data) {
832 wpa_hexdump_key(MSG_MSGDUMP,
833 "PKCS #12: Decrypted encryptedContent",
834 data, data_len);
835 res = pkcs12_safecontents(cred, data, data_len, passwd);
836 os_free(data);
837 }
838
839 return res;
840}
841
842
843static int pkcs12_parse_content(struct tlsv1_credentials *cred,
844 const u8 *buf, size_t len,
845 const char *passwd)
846{
847 const u8 *pos = buf;
848 const u8 *end = buf + len;
849 struct asn1_oid oid;
850 char txt[80];
851 struct asn1_hdr hdr;
852
853 wpa_hexdump(MSG_MSGDUMP, "PKCS #12: ContentInfo", buf, len);
854
855 if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
856 wpa_printf(MSG_DEBUG,
857 "PKCS #12: Could not find OBJECT IDENTIFIER (contentType)");
858 return 0;
859 }
860
861 asn1_oid_to_str(&oid, txt, sizeof(txt));
862 wpa_printf(MSG_DEBUG, "PKCS #12: contentType %s", txt);
863
Hai Shalomc1a21442022-02-04 13:43:00 -0800864 if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed ||
865 !asn1_is_cs_tag(&hdr, 0)) {
866 asn1_unexpected(&hdr,
867 "PKCS #12: Expected [0] EXPLICIT (content)");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800868 return 0;
869 }
870 pos = hdr.payload;
871
872 if (is_oid_pkcs7_data(&oid))
873 return pkcs12_parse_content_data(cred, pos, end, passwd);
874 if (is_oid_pkcs7_enc_data(&oid))
875 return pkcs12_parse_content_enc_data(cred, pos, end, passwd);
876
877 wpa_printf(MSG_DEBUG, "PKCS #12: Ignored unsupported contentType %s",
878 txt);
879
880 return 0;
881}
882
883
884static int pkcs12_parse(struct tlsv1_credentials *cred,
885 const u8 *key, size_t len, const char *passwd)
886{
887 struct asn1_hdr hdr;
888 const u8 *pos, *end;
889 struct asn1_oid oid;
890 char buf[80];
891
892 /*
893 * PFX ::= SEQUENCE {
894 * version INTEGER {v3(3)}(v3,...),
895 * authSafe ContentInfo,
896 * macData MacData OPTIONAL
897 * }
898 */
899
Hai Shalomc1a21442022-02-04 13:43:00 -0800900 if (asn1_get_next(key, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
901 asn1_unexpected(&hdr,
902 "PKCS #12: Expected SEQUENCE (PFX); assume PKCS #12 not used");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800903 return -1;
904 }
905
906 pos = hdr.payload;
907 end = pos + hdr.length;
908
Hai Shalomc1a21442022-02-04 13:43:00 -0800909 if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_integer(&hdr)) {
910 asn1_unexpected(&hdr,
911 "PKCS #12: No INTEGER tag found for version");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800912 return -1;
913 }
914 if (hdr.length != 1 || hdr.payload[0] != 3) {
915 wpa_printf(MSG_DEBUG, "PKCS #12: Unrecognized version");
916 return -1;
917 }
918 pos = hdr.payload + hdr.length;
919
920 /*
921 * ContentInfo ::= SEQUENCE {
922 * contentType ContentType,
923 * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
924 */
925
926 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
Hai Shalomc1a21442022-02-04 13:43:00 -0800927 !asn1_is_sequence(&hdr)) {
928 asn1_unexpected(&hdr,
929 "PKCS #12: Expected SEQUENCE (authSafe); assume PKCS #12 not used");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800930 return -1;
931 }
932
933 pos = hdr.payload;
934 end = pos + hdr.length;
935
936 /* ContentType ::= OBJECT IDENTIFIER */
937 if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
938 wpa_printf(MSG_DEBUG,
939 "PKCS #12: Could not find OBJECT IDENTIFIER (contentType); assume PKCS #12 not used");
940 return -1;
941 }
942 asn1_oid_to_str(&oid, buf, sizeof(buf));
943 wpa_printf(MSG_DEBUG, "PKCS #12: contentType %s", buf);
944 if (!is_oid_pkcs7_data(&oid)) {
945 wpa_printf(MSG_DEBUG, "PKCS #12: Unsupported contentType %s",
946 buf);
947 return -1;
948 }
949
Hai Shalomc1a21442022-02-04 13:43:00 -0800950 if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed ||
951 !asn1_is_cs_tag(&hdr, 0)) {
952 asn1_unexpected(&hdr,
953 "PKCS #12: Expected [0] EXPLICIT (content); assume PKCS #12 not used");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800954 return -1;
955 }
956
957 pos = hdr.payload;
958
959 /* Data ::= OCTET STRING */
960 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
Hai Shalomc1a21442022-02-04 13:43:00 -0800961 !asn1_is_octetstring(&hdr)) {
962 asn1_unexpected(&hdr,
963 "PKCS #12: Expected OCTET STRING (Data); assume PKCS #12 not used");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800964 return -1;
965 }
966
967 /*
968 * AuthenticatedSafe ::= SEQUENCE OF ContentInfo
969 * -- Data if unencrypted
970 * -- EncryptedData if password-encrypted
971 * -- EnvelopedData if public key-encrypted
972 */
973 wpa_hexdump(MSG_MSGDUMP, "PKCS #12: Data content",
974 hdr.payload, hdr.length);
975
976 if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
Hai Shalomc1a21442022-02-04 13:43:00 -0800977 !asn1_is_sequence(&hdr)) {
978 asn1_unexpected(&hdr,
979 "PKCS #12: Expected SEQUENCE within Data content; assume PKCS #12 not used");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800980 return -1;
981 }
982
983 pos = hdr.payload;
984 end = pos + hdr.length;
985
986 while (end > pos) {
987 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
Hai Shalomc1a21442022-02-04 13:43:00 -0800988 !asn1_is_sequence(&hdr)) {
989 asn1_unexpected(&hdr,
990 "PKCS #12: Expected SEQUENCE (ContentInfo); assume PKCS #12 not used");
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800991 return -1;
992 }
993 if (pkcs12_parse_content(cred, hdr.payload, hdr.length,
994 passwd) < 0)
995 return -1;
996
997 pos = hdr.payload + hdr.length;
998 }
999
1000 return 0;
1001}
1002
1003#endif /* PKCS12_FUNCS */
1004
1005
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001006static int tlsv1_set_key(struct tlsv1_credentials *cred,
1007 const u8 *key, size_t len, const char *passwd)
1008{
1009 cred->key = crypto_private_key_import(key, len, passwd);
1010 if (cred->key == NULL)
1011 cred->key = tlsv1_set_key_pem(key, len);
1012 if (cred->key == NULL)
1013 cred->key = tlsv1_set_key_enc_pem(key, len, passwd);
Dmitry Shmidt1b467752015-12-14 12:45:46 -08001014#ifdef PKCS12_FUNCS
1015 if (!cred->key)
1016 pkcs12_parse(cred, key, len, passwd);
1017#endif /* PKCS12_FUNCS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001018 if (cred->key == NULL) {
1019 wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
1020 return -1;
1021 }
1022 return 0;
1023}
1024
1025
1026/**
1027 * tlsv1_set_private_key - Set private key
1028 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
1029 * @private_key: File or reference name for the key in PEM or DER format
1030 * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
1031 * passphrase is used.
1032 * @private_key_blob: private_key as inlined data or %NULL if not used
1033 * @private_key_blob_len: private_key_blob length
1034 * Returns: 0 on success, -1 on failure
1035 */
1036int tlsv1_set_private_key(struct tlsv1_credentials *cred,
1037 const char *private_key,
1038 const char *private_key_passwd,
1039 const u8 *private_key_blob,
1040 size_t private_key_blob_len)
1041{
1042 crypto_private_key_free(cred->key);
1043 cred->key = NULL;
1044
1045 if (private_key_blob)
1046 return tlsv1_set_key(cred, private_key_blob,
1047 private_key_blob_len,
1048 private_key_passwd);
1049
1050 if (private_key) {
1051 u8 *buf;
1052 size_t len;
1053 int ret;
1054
1055 buf = (u8 *) os_readfile(private_key, &len);
1056 if (buf == NULL) {
1057 wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
1058 private_key);
1059 return -1;
1060 }
1061
1062 ret = tlsv1_set_key(cred, buf, len, private_key_passwd);
1063 os_free(buf);
1064 return ret;
1065 }
1066
1067 return 0;
1068}
1069
1070
1071static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
1072 const u8 *dh, size_t len)
1073{
1074 struct asn1_hdr hdr;
1075 const u8 *pos, *end;
1076
1077 pos = dh;
1078 end = dh + len;
1079
1080 /*
1081 * DHParameter ::= SEQUENCE {
1082 * prime INTEGER, -- p
1083 * base INTEGER, -- g
1084 * privateValueLength INTEGER OPTIONAL }
1085 */
1086
1087 /* DHParamer ::= SEQUENCE */
Hai Shalomc1a21442022-02-04 13:43:00 -08001088 if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
1089 asn1_unexpected(&hdr,
1090 "DH: DH parameters did not start with a valid SEQUENCE");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001091 return -1;
1092 }
1093 pos = hdr.payload;
1094
1095 /* prime INTEGER */
Hai Shalomc1a21442022-02-04 13:43:00 -08001096 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1097 !asn1_is_integer(&hdr)) {
1098 asn1_unexpected(&hdr, "DH: No INTEGER tag found for p");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001099 return -1;
1100 }
1101
1102 wpa_hexdump(MSG_MSGDUMP, "DH: prime (p)", hdr.payload, hdr.length);
1103 if (hdr.length == 0)
1104 return -1;
1105 os_free(cred->dh_p);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001106 cred->dh_p = os_memdup(hdr.payload, hdr.length);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001107 if (cred->dh_p == NULL)
1108 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001109 cred->dh_p_len = hdr.length;
1110 pos = hdr.payload + hdr.length;
1111
1112 /* base INTEGER */
Hai Shalomc1a21442022-02-04 13:43:00 -08001113 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1114 !asn1_is_integer(&hdr)) {
1115 asn1_unexpected(&hdr, "DH: No INTEGER tag found for g");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001116 return -1;
1117 }
1118
1119 wpa_hexdump(MSG_MSGDUMP, "DH: base (g)", hdr.payload, hdr.length);
1120 if (hdr.length == 0)
1121 return -1;
1122 os_free(cred->dh_g);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001123 cred->dh_g = os_memdup(hdr.payload, hdr.length);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001124 if (cred->dh_g == NULL)
1125 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001126 cred->dh_g_len = hdr.length;
1127
1128 return 0;
1129}
1130
1131
1132static const char *pem_dhparams_begin = "-----BEGIN DH PARAMETERS-----";
1133static const char *pem_dhparams_end = "-----END DH PARAMETERS-----";
1134
1135
1136static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred,
1137 const u8 *buf, size_t len)
1138{
1139 const u8 *pos, *end;
1140 unsigned char *der;
1141 size_t der_len;
1142
1143 pos = search_tag(pem_dhparams_begin, buf, len);
1144 if (!pos) {
1145 wpa_printf(MSG_DEBUG, "TLSv1: No PEM dhparams tag found - "
1146 "assume DER format");
1147 return tlsv1_set_dhparams_der(cred, buf, len);
1148 }
1149
1150 wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format dhparams into DER "
1151 "format");
1152
1153 pos += os_strlen(pem_dhparams_begin);
1154 end = search_tag(pem_dhparams_end, pos, buf + len - pos);
1155 if (end == NULL) {
1156 wpa_printf(MSG_INFO, "TLSv1: Could not find PEM dhparams end "
1157 "tag (%s)", pem_dhparams_end);
1158 return -1;
1159 }
1160
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001161 der = base64_decode((const char *) pos, end - pos, &der_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001162 if (der == NULL) {
1163 wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams");
1164 return -1;
1165 }
1166
1167 if (tlsv1_set_dhparams_der(cred, der, der_len) < 0) {
1168 wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM dhparams "
1169 "DER conversion");
1170 os_free(der);
1171 return -1;
1172 }
1173
1174 os_free(der);
1175
1176 return 0;
1177}
1178
1179
1180/**
1181 * tlsv1_set_dhparams - Set Diffie-Hellman parameters
1182 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
1183 * @dh_file: File or reference name for the DH params in PEM or DER format
1184 * @dh_blob: DH params as inlined data or %NULL if not used
1185 * @dh_blob_len: dh_blob length
1186 * Returns: 0 on success, -1 on failure
1187 */
1188int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,
1189 const u8 *dh_blob, size_t dh_blob_len)
1190{
1191 if (dh_blob)
1192 return tlsv1_set_dhparams_blob(cred, dh_blob, dh_blob_len);
1193
1194 if (dh_file) {
1195 u8 *buf;
1196 size_t len;
1197 int ret;
1198
1199 buf = (u8 *) os_readfile(dh_file, &len);
1200 if (buf == NULL) {
1201 wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
1202 dh_file);
1203 return -1;
1204 }
1205
1206 ret = tlsv1_set_dhparams_blob(cred, buf, len);
1207 os_free(buf);
1208 return ret;
1209 }
1210
1211 return 0;
1212}