139beb93cSSam Leffler /*
239beb93cSSam Leffler * TLSv1 credentials
3780fb4a2SCy Schubert * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler *
5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo * See README for more details.
739beb93cSSam Leffler */
839beb93cSSam Leffler
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler
1139beb93cSSam Leffler #include "common.h"
1239beb93cSSam Leffler #include "base64.h"
13e28a4053SRui Paulo #include "crypto/crypto.h"
14780fb4a2SCy Schubert #include "crypto/sha1.h"
15780fb4a2SCy Schubert #include "pkcs5.h"
16780fb4a2SCy Schubert #include "pkcs8.h"
1739beb93cSSam Leffler #include "x509v3.h"
1839beb93cSSam Leffler #include "tlsv1_cred.h"
1939beb93cSSam Leffler
2039beb93cSSam Leffler
tlsv1_cred_alloc(void)2139beb93cSSam Leffler struct tlsv1_credentials * tlsv1_cred_alloc(void)
2239beb93cSSam Leffler {
2339beb93cSSam Leffler struct tlsv1_credentials *cred;
2439beb93cSSam Leffler cred = os_zalloc(sizeof(*cred));
2539beb93cSSam Leffler return cred;
2639beb93cSSam Leffler }
2739beb93cSSam Leffler
2839beb93cSSam Leffler
tlsv1_cred_free(struct tlsv1_credentials * cred)2939beb93cSSam Leffler void tlsv1_cred_free(struct tlsv1_credentials *cred)
3039beb93cSSam Leffler {
3139beb93cSSam Leffler if (cred == NULL)
3239beb93cSSam Leffler return;
3339beb93cSSam Leffler
3439beb93cSSam Leffler x509_certificate_chain_free(cred->trusted_certs);
3539beb93cSSam Leffler x509_certificate_chain_free(cred->cert);
3639beb93cSSam Leffler crypto_private_key_free(cred->key);
3739beb93cSSam Leffler os_free(cred->dh_p);
3839beb93cSSam Leffler os_free(cred->dh_g);
39780fb4a2SCy Schubert os_free(cred->ocsp_stapling_response);
40780fb4a2SCy Schubert os_free(cred->ocsp_stapling_response_multi);
4139beb93cSSam Leffler os_free(cred);
4239beb93cSSam Leffler }
4339beb93cSSam Leffler
4439beb93cSSam Leffler
tlsv1_add_cert_der(struct x509_certificate ** chain,const u8 * buf,size_t len)4539beb93cSSam Leffler static int tlsv1_add_cert_der(struct x509_certificate **chain,
4639beb93cSSam Leffler const u8 *buf, size_t len)
4739beb93cSSam Leffler {
48f05cddf9SRui Paulo struct x509_certificate *cert, *p;
4939beb93cSSam Leffler char name[128];
5039beb93cSSam Leffler
5139beb93cSSam Leffler cert = x509_certificate_parse(buf, len);
5239beb93cSSam Leffler if (cert == NULL) {
5339beb93cSSam Leffler wpa_printf(MSG_INFO, "TLSv1: %s - failed to parse certificate",
5439beb93cSSam Leffler __func__);
5539beb93cSSam Leffler return -1;
5639beb93cSSam Leffler }
5739beb93cSSam Leffler
58f05cddf9SRui Paulo p = *chain;
59f05cddf9SRui Paulo while (p && p->next)
60f05cddf9SRui Paulo p = p->next;
61f05cddf9SRui Paulo if (p && x509_name_compare(&cert->subject, &p->issuer) == 0) {
62f05cddf9SRui Paulo /*
63f05cddf9SRui Paulo * The new certificate is the issuer of the last certificate in
64f05cddf9SRui Paulo * the chain - add the new certificate to the end.
65f05cddf9SRui Paulo */
66f05cddf9SRui Paulo p->next = cert;
67f05cddf9SRui Paulo } else {
68f05cddf9SRui Paulo /* Add to the beginning of the chain */
6939beb93cSSam Leffler cert->next = *chain;
7039beb93cSSam Leffler *chain = cert;
71f05cddf9SRui Paulo }
7239beb93cSSam Leffler
7339beb93cSSam Leffler x509_name_string(&cert->subject, name, sizeof(name));
7439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name);
7539beb93cSSam Leffler
7639beb93cSSam Leffler return 0;
7739beb93cSSam Leffler }
7839beb93cSSam Leffler
7939beb93cSSam Leffler
8039beb93cSSam Leffler static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----";
8139beb93cSSam Leffler static const char *pem_cert_end = "-----END CERTIFICATE-----";
82e28a4053SRui Paulo static const char *pem_key_begin = "-----BEGIN RSA PRIVATE KEY-----";
83e28a4053SRui Paulo static const char *pem_key_end = "-----END RSA PRIVATE KEY-----";
84e28a4053SRui Paulo static const char *pem_key2_begin = "-----BEGIN PRIVATE KEY-----";
85e28a4053SRui Paulo static const char *pem_key2_end = "-----END PRIVATE KEY-----";
86e28a4053SRui Paulo static const char *pem_key_enc_begin = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
87e28a4053SRui Paulo static const char *pem_key_enc_end = "-----END ENCRYPTED PRIVATE KEY-----";
8839beb93cSSam Leffler
8939beb93cSSam Leffler
search_tag(const char * tag,const u8 * buf,size_t len)9039beb93cSSam Leffler static const u8 * search_tag(const char *tag, const u8 *buf, size_t len)
9139beb93cSSam Leffler {
9239beb93cSSam Leffler size_t i, plen;
9339beb93cSSam Leffler
9439beb93cSSam Leffler plen = os_strlen(tag);
9539beb93cSSam Leffler if (len < plen)
9639beb93cSSam Leffler return NULL;
9739beb93cSSam Leffler
9839beb93cSSam Leffler for (i = 0; i < len - plen; i++) {
9939beb93cSSam Leffler if (os_memcmp(buf + i, tag, plen) == 0)
10039beb93cSSam Leffler return buf + i;
10139beb93cSSam Leffler }
10239beb93cSSam Leffler
10339beb93cSSam Leffler return NULL;
10439beb93cSSam Leffler }
10539beb93cSSam Leffler
10639beb93cSSam Leffler
tlsv1_add_cert(struct x509_certificate ** chain,const u8 * buf,size_t len)10739beb93cSSam Leffler static int tlsv1_add_cert(struct x509_certificate **chain,
10839beb93cSSam Leffler const u8 *buf, size_t len)
10939beb93cSSam Leffler {
11039beb93cSSam Leffler const u8 *pos, *end;
11139beb93cSSam Leffler unsigned char *der;
11239beb93cSSam Leffler size_t der_len;
11339beb93cSSam Leffler
11439beb93cSSam Leffler pos = search_tag(pem_cert_begin, buf, len);
11539beb93cSSam Leffler if (!pos) {
11639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: No PEM certificate tag found - "
11739beb93cSSam Leffler "assume DER format");
11839beb93cSSam Leffler return tlsv1_add_cert_der(chain, buf, len);
11939beb93cSSam Leffler }
12039beb93cSSam Leffler
12139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format certificate into "
12239beb93cSSam Leffler "DER format");
12339beb93cSSam Leffler
12439beb93cSSam Leffler while (pos) {
12539beb93cSSam Leffler pos += os_strlen(pem_cert_begin);
12639beb93cSSam Leffler end = search_tag(pem_cert_end, pos, buf + len - pos);
12739beb93cSSam Leffler if (end == NULL) {
12839beb93cSSam Leffler wpa_printf(MSG_INFO, "TLSv1: Could not find PEM "
12939beb93cSSam Leffler "certificate end tag (%s)", pem_cert_end);
13039beb93cSSam Leffler return -1;
13139beb93cSSam Leffler }
13239beb93cSSam Leffler
133*c1d255d3SCy Schubert der = base64_decode((const char *) pos, end - pos, &der_len);
13439beb93cSSam Leffler if (der == NULL) {
13539beb93cSSam Leffler wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
13639beb93cSSam Leffler "certificate");
13739beb93cSSam Leffler return -1;
13839beb93cSSam Leffler }
13939beb93cSSam Leffler
14039beb93cSSam Leffler if (tlsv1_add_cert_der(chain, der, der_len) < 0) {
14139beb93cSSam Leffler wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM "
14239beb93cSSam Leffler "certificate after DER conversion");
14339beb93cSSam Leffler os_free(der);
14439beb93cSSam Leffler return -1;
14539beb93cSSam Leffler }
14639beb93cSSam Leffler
14739beb93cSSam Leffler os_free(der);
14839beb93cSSam Leffler
14939beb93cSSam Leffler end += os_strlen(pem_cert_end);
15039beb93cSSam Leffler pos = search_tag(pem_cert_begin, end, buf + len - end);
15139beb93cSSam Leffler }
15239beb93cSSam Leffler
15339beb93cSSam Leffler return 0;
15439beb93cSSam Leffler }
15539beb93cSSam Leffler
15639beb93cSSam Leffler
tlsv1_set_cert_chain(struct x509_certificate ** chain,const char * cert,const u8 * cert_blob,size_t cert_blob_len)15739beb93cSSam Leffler static int tlsv1_set_cert_chain(struct x509_certificate **chain,
15839beb93cSSam Leffler const char *cert, const u8 *cert_blob,
15939beb93cSSam Leffler size_t cert_blob_len)
16039beb93cSSam Leffler {
16139beb93cSSam Leffler if (cert_blob)
16239beb93cSSam Leffler return tlsv1_add_cert(chain, cert_blob, cert_blob_len);
16339beb93cSSam Leffler
16439beb93cSSam Leffler if (cert) {
16539beb93cSSam Leffler u8 *buf;
16639beb93cSSam Leffler size_t len;
16739beb93cSSam Leffler int ret;
16839beb93cSSam Leffler
16939beb93cSSam Leffler buf = (u8 *) os_readfile(cert, &len);
17039beb93cSSam Leffler if (buf == NULL) {
17139beb93cSSam Leffler wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
17239beb93cSSam Leffler cert);
17339beb93cSSam Leffler return -1;
17439beb93cSSam Leffler }
17539beb93cSSam Leffler
17639beb93cSSam Leffler ret = tlsv1_add_cert(chain, buf, len);
17739beb93cSSam Leffler os_free(buf);
17839beb93cSSam Leffler return ret;
17939beb93cSSam Leffler }
18039beb93cSSam Leffler
18139beb93cSSam Leffler return 0;
18239beb93cSSam Leffler }
18339beb93cSSam Leffler
18439beb93cSSam Leffler
18539beb93cSSam Leffler /**
18639beb93cSSam Leffler * tlsv1_set_ca_cert - Set trusted CA certificate(s)
18739beb93cSSam Leffler * @cred: TLSv1 credentials from tlsv1_cred_alloc()
18839beb93cSSam Leffler * @cert: File or reference name for X.509 certificate in PEM or DER format
18939beb93cSSam Leffler * @cert_blob: cert as inlined data or %NULL if not used
19039beb93cSSam Leffler * @cert_blob_len: ca_cert_blob length
19139beb93cSSam Leffler * @path: Path to CA certificates (not yet supported)
19239beb93cSSam Leffler * Returns: 0 on success, -1 on failure
19339beb93cSSam Leffler */
tlsv1_set_ca_cert(struct tlsv1_credentials * cred,const char * cert,const u8 * cert_blob,size_t cert_blob_len,const char * path)19439beb93cSSam Leffler int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
19539beb93cSSam Leffler const u8 *cert_blob, size_t cert_blob_len,
19639beb93cSSam Leffler const char *path)
19739beb93cSSam Leffler {
198780fb4a2SCy Schubert if (cert && os_strncmp(cert, "hash://", 7) == 0) {
199780fb4a2SCy Schubert const char *pos = cert + 7;
200780fb4a2SCy Schubert if (os_strncmp(pos, "server/sha256/", 14) != 0) {
201780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
202780fb4a2SCy Schubert "TLSv1: Unsupported ca_cert hash value '%s'",
203780fb4a2SCy Schubert cert);
204780fb4a2SCy Schubert return -1;
205780fb4a2SCy Schubert }
206780fb4a2SCy Schubert pos += 14;
207780fb4a2SCy Schubert if (os_strlen(pos) != 32 * 2) {
208780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
209780fb4a2SCy Schubert "TLSv1: Unexpected SHA256 hash length in ca_cert '%s'",
210780fb4a2SCy Schubert cert);
211780fb4a2SCy Schubert return -1;
212780fb4a2SCy Schubert }
213780fb4a2SCy Schubert if (hexstr2bin(pos, cred->srv_cert_hash, 32) < 0) {
214780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
215780fb4a2SCy Schubert "TLSv1: Invalid SHA256 hash value in ca_cert '%s'",
216780fb4a2SCy Schubert cert);
217780fb4a2SCy Schubert return -1;
218780fb4a2SCy Schubert }
219780fb4a2SCy Schubert cred->server_cert_only = 1;
220780fb4a2SCy Schubert cred->ca_cert_verify = 0;
221780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
222780fb4a2SCy Schubert "TLSv1: Checking only server certificate match");
223780fb4a2SCy Schubert return 0;
224780fb4a2SCy Schubert }
225780fb4a2SCy Schubert
226780fb4a2SCy Schubert if (cert && os_strncmp(cert, "probe://", 8) == 0) {
227780fb4a2SCy Schubert cred->cert_probe = 1;
228780fb4a2SCy Schubert cred->ca_cert_verify = 0;
229780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "TLSv1: Only probe server certificate");
230780fb4a2SCy Schubert return 0;
231780fb4a2SCy Schubert }
232780fb4a2SCy Schubert
233780fb4a2SCy Schubert cred->ca_cert_verify = cert || cert_blob || path;
234780fb4a2SCy Schubert
23539beb93cSSam Leffler if (tlsv1_set_cert_chain(&cred->trusted_certs, cert,
23639beb93cSSam Leffler cert_blob, cert_blob_len) < 0)
23739beb93cSSam Leffler return -1;
23839beb93cSSam Leffler
23939beb93cSSam Leffler if (path) {
24039beb93cSSam Leffler /* TODO: add support for reading number of certificate files */
24139beb93cSSam Leffler wpa_printf(MSG_INFO, "TLSv1: Use of CA certificate directory "
24239beb93cSSam Leffler "not yet supported");
24339beb93cSSam Leffler return -1;
24439beb93cSSam Leffler }
24539beb93cSSam Leffler
24639beb93cSSam Leffler return 0;
24739beb93cSSam Leffler }
24839beb93cSSam Leffler
24939beb93cSSam Leffler
25039beb93cSSam Leffler /**
25139beb93cSSam Leffler * tlsv1_set_cert - Set certificate
25239beb93cSSam Leffler * @cred: TLSv1 credentials from tlsv1_cred_alloc()
25339beb93cSSam Leffler * @cert: File or reference name for X.509 certificate in PEM or DER format
25439beb93cSSam Leffler * @cert_blob: cert as inlined data or %NULL if not used
25539beb93cSSam Leffler * @cert_blob_len: cert_blob length
25639beb93cSSam Leffler * Returns: 0 on success, -1 on failure
25739beb93cSSam Leffler */
tlsv1_set_cert(struct tlsv1_credentials * cred,const char * cert,const u8 * cert_blob,size_t cert_blob_len)25839beb93cSSam Leffler int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert,
25939beb93cSSam Leffler const u8 *cert_blob, size_t cert_blob_len)
26039beb93cSSam Leffler {
26139beb93cSSam Leffler return tlsv1_set_cert_chain(&cred->cert, cert,
26239beb93cSSam Leffler cert_blob, cert_blob_len);
26339beb93cSSam Leffler }
26439beb93cSSam Leffler
26539beb93cSSam Leffler
tlsv1_set_key_pem(const u8 * key,size_t len)266e28a4053SRui Paulo static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len)
26739beb93cSSam Leffler {
268e28a4053SRui Paulo const u8 *pos, *end;
269e28a4053SRui Paulo unsigned char *der;
270e28a4053SRui Paulo size_t der_len;
271e28a4053SRui Paulo struct crypto_private_key *pkey;
272e28a4053SRui Paulo
273e28a4053SRui Paulo pos = search_tag(pem_key_begin, key, len);
274e28a4053SRui Paulo if (!pos) {
275e28a4053SRui Paulo pos = search_tag(pem_key2_begin, key, len);
276e28a4053SRui Paulo if (!pos)
277e28a4053SRui Paulo return NULL;
278e28a4053SRui Paulo pos += os_strlen(pem_key2_begin);
279e28a4053SRui Paulo end = search_tag(pem_key2_end, pos, key + len - pos);
280e28a4053SRui Paulo if (!end)
281e28a4053SRui Paulo return NULL;
282e28a4053SRui Paulo } else {
283f05cddf9SRui Paulo const u8 *pos2;
284e28a4053SRui Paulo pos += os_strlen(pem_key_begin);
285e28a4053SRui Paulo end = search_tag(pem_key_end, pos, key + len - pos);
286e28a4053SRui Paulo if (!end)
287e28a4053SRui Paulo return NULL;
288f05cddf9SRui Paulo pos2 = search_tag("Proc-Type: 4,ENCRYPTED", pos, end - pos);
289f05cddf9SRui Paulo if (pos2) {
290f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TLSv1: Unsupported private key "
291f05cddf9SRui Paulo "format (Proc-Type/DEK-Info)");
292f05cddf9SRui Paulo return NULL;
293f05cddf9SRui Paulo }
294e28a4053SRui Paulo }
295e28a4053SRui Paulo
296*c1d255d3SCy Schubert der = base64_decode((const char *) pos, end - pos, &der_len);
297e28a4053SRui Paulo if (!der)
298e28a4053SRui Paulo return NULL;
299e28a4053SRui Paulo pkey = crypto_private_key_import(der, der_len, NULL);
300e28a4053SRui Paulo os_free(der);
301e28a4053SRui Paulo return pkey;
302e28a4053SRui Paulo }
303e28a4053SRui Paulo
304e28a4053SRui Paulo
tlsv1_set_key_enc_pem(const u8 * key,size_t len,const char * passwd)305e28a4053SRui Paulo static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key,
306e28a4053SRui Paulo size_t len,
307e28a4053SRui Paulo const char *passwd)
308e28a4053SRui Paulo {
309e28a4053SRui Paulo const u8 *pos, *end;
310e28a4053SRui Paulo unsigned char *der;
311e28a4053SRui Paulo size_t der_len;
312e28a4053SRui Paulo struct crypto_private_key *pkey;
313e28a4053SRui Paulo
314e28a4053SRui Paulo if (passwd == NULL)
315e28a4053SRui Paulo return NULL;
316e28a4053SRui Paulo pos = search_tag(pem_key_enc_begin, key, len);
317e28a4053SRui Paulo if (!pos)
318e28a4053SRui Paulo return NULL;
319e28a4053SRui Paulo pos += os_strlen(pem_key_enc_begin);
320e28a4053SRui Paulo end = search_tag(pem_key_enc_end, pos, key + len - pos);
321e28a4053SRui Paulo if (!end)
322e28a4053SRui Paulo return NULL;
323e28a4053SRui Paulo
324*c1d255d3SCy Schubert der = base64_decode((const char *) pos, end - pos, &der_len);
325e28a4053SRui Paulo if (!der)
326e28a4053SRui Paulo return NULL;
327e28a4053SRui Paulo pkey = crypto_private_key_import(der, der_len, passwd);
328e28a4053SRui Paulo os_free(der);
329e28a4053SRui Paulo return pkey;
330e28a4053SRui Paulo }
331e28a4053SRui Paulo
332e28a4053SRui Paulo
333780fb4a2SCy Schubert #ifdef PKCS12_FUNCS
334780fb4a2SCy Schubert
oid_is_rsadsi(struct asn1_oid * oid)335780fb4a2SCy Schubert static int oid_is_rsadsi(struct asn1_oid *oid)
336780fb4a2SCy Schubert {
337780fb4a2SCy Schubert return oid->len >= 4 &&
338780fb4a2SCy Schubert oid->oid[0] == 1 /* iso */ &&
339780fb4a2SCy Schubert oid->oid[1] == 2 /* member-body */ &&
340780fb4a2SCy Schubert oid->oid[2] == 840 /* us */ &&
341780fb4a2SCy Schubert oid->oid[3] == 113549 /* rsadsi */;
342780fb4a2SCy Schubert }
343780fb4a2SCy Schubert
344780fb4a2SCy Schubert
pkcs12_is_bagtype_oid(struct asn1_oid * oid,unsigned long type)345780fb4a2SCy Schubert static int pkcs12_is_bagtype_oid(struct asn1_oid *oid, unsigned long type)
346780fb4a2SCy Schubert {
347780fb4a2SCy Schubert return oid->len == 9 &&
348780fb4a2SCy Schubert oid_is_rsadsi(oid) &&
349780fb4a2SCy Schubert oid->oid[4] == 1 /* pkcs */ &&
350780fb4a2SCy Schubert oid->oid[5] == 12 /* pkcs-12 */ &&
351780fb4a2SCy Schubert oid->oid[6] == 10 &&
352780fb4a2SCy Schubert oid->oid[7] == 1 /* bagtypes */ &&
353780fb4a2SCy Schubert oid->oid[8] == type;
354780fb4a2SCy Schubert }
355780fb4a2SCy Schubert
356780fb4a2SCy Schubert
is_oid_pkcs7(struct asn1_oid * oid)357780fb4a2SCy Schubert static int is_oid_pkcs7(struct asn1_oid *oid)
358780fb4a2SCy Schubert {
359780fb4a2SCy Schubert return oid->len == 7 &&
360780fb4a2SCy Schubert oid->oid[0] == 1 /* iso */ &&
361780fb4a2SCy Schubert oid->oid[1] == 2 /* member-body */ &&
362780fb4a2SCy Schubert oid->oid[2] == 840 /* us */ &&
363780fb4a2SCy Schubert oid->oid[3] == 113549 /* rsadsi */ &&
364780fb4a2SCy Schubert oid->oid[4] == 1 /* pkcs */ &&
365780fb4a2SCy Schubert oid->oid[5] == 7 /* pkcs-7 */;
366780fb4a2SCy Schubert }
367780fb4a2SCy Schubert
368780fb4a2SCy Schubert
is_oid_pkcs7_data(struct asn1_oid * oid)369780fb4a2SCy Schubert static int is_oid_pkcs7_data(struct asn1_oid *oid)
370780fb4a2SCy Schubert {
371780fb4a2SCy Schubert return is_oid_pkcs7(oid) && oid->oid[6] == 1 /* data */;
372780fb4a2SCy Schubert }
373780fb4a2SCy Schubert
374780fb4a2SCy Schubert
is_oid_pkcs7_enc_data(struct asn1_oid * oid)375780fb4a2SCy Schubert static int is_oid_pkcs7_enc_data(struct asn1_oid *oid)
376780fb4a2SCy Schubert {
377780fb4a2SCy Schubert return is_oid_pkcs7(oid) && oid->oid[6] == 6 /* encryptedData */;
378780fb4a2SCy Schubert }
379780fb4a2SCy Schubert
380780fb4a2SCy Schubert
is_oid_pkcs9(struct asn1_oid * oid)381780fb4a2SCy Schubert static int is_oid_pkcs9(struct asn1_oid *oid)
382780fb4a2SCy Schubert {
383780fb4a2SCy Schubert return oid->len >= 6 &&
384780fb4a2SCy Schubert oid->oid[0] == 1 /* iso */ &&
385780fb4a2SCy Schubert oid->oid[1] == 2 /* member-body */ &&
386780fb4a2SCy Schubert oid->oid[2] == 840 /* us */ &&
387780fb4a2SCy Schubert oid->oid[3] == 113549 /* rsadsi */ &&
388780fb4a2SCy Schubert oid->oid[4] == 1 /* pkcs */ &&
389780fb4a2SCy Schubert oid->oid[5] == 9 /* pkcs-9 */;
390780fb4a2SCy Schubert }
391780fb4a2SCy Schubert
392780fb4a2SCy Schubert
is_oid_pkcs9_friendly_name(struct asn1_oid * oid)393780fb4a2SCy Schubert static int is_oid_pkcs9_friendly_name(struct asn1_oid *oid)
394780fb4a2SCy Schubert {
395780fb4a2SCy Schubert return oid->len == 7 && is_oid_pkcs9(oid) &&
396780fb4a2SCy Schubert oid->oid[6] == 20;
397780fb4a2SCy Schubert }
398780fb4a2SCy Schubert
399780fb4a2SCy Schubert
is_oid_pkcs9_local_key_id(struct asn1_oid * oid)400780fb4a2SCy Schubert static int is_oid_pkcs9_local_key_id(struct asn1_oid *oid)
401780fb4a2SCy Schubert {
402780fb4a2SCy Schubert return oid->len == 7 && is_oid_pkcs9(oid) &&
403780fb4a2SCy Schubert oid->oid[6] == 21;
404780fb4a2SCy Schubert }
405780fb4a2SCy Schubert
406780fb4a2SCy Schubert
is_oid_pkcs9_x509_cert(struct asn1_oid * oid)407780fb4a2SCy Schubert static int is_oid_pkcs9_x509_cert(struct asn1_oid *oid)
408780fb4a2SCy Schubert {
409780fb4a2SCy Schubert return oid->len == 8 && is_oid_pkcs9(oid) &&
410780fb4a2SCy Schubert oid->oid[6] == 22 /* certTypes */ &&
411780fb4a2SCy Schubert oid->oid[7] == 1 /* x509Certificate */;
412780fb4a2SCy Schubert }
413780fb4a2SCy Schubert
414780fb4a2SCy Schubert
pkcs12_keybag(struct tlsv1_credentials * cred,const u8 * buf,size_t len)415780fb4a2SCy Schubert static int pkcs12_keybag(struct tlsv1_credentials *cred,
416780fb4a2SCy Schubert const u8 *buf, size_t len)
417780fb4a2SCy Schubert {
418780fb4a2SCy Schubert /* TODO */
419780fb4a2SCy Schubert return 0;
420780fb4a2SCy Schubert }
421780fb4a2SCy Schubert
422780fb4a2SCy Schubert
pkcs12_pkcs8_keybag(struct tlsv1_credentials * cred,const u8 * buf,size_t len,const char * passwd)423780fb4a2SCy Schubert static int pkcs12_pkcs8_keybag(struct tlsv1_credentials *cred,
424780fb4a2SCy Schubert const u8 *buf, size_t len,
425780fb4a2SCy Schubert const char *passwd)
426780fb4a2SCy Schubert {
427780fb4a2SCy Schubert struct crypto_private_key *key;
428780fb4a2SCy Schubert
429780fb4a2SCy Schubert /* PKCS8ShroudedKeyBag ::= EncryptedPrivateKeyInfo */
430780fb4a2SCy Schubert key = pkcs8_enc_key_import(buf, len, passwd);
431780fb4a2SCy Schubert if (!key)
432780fb4a2SCy Schubert return -1;
433780fb4a2SCy Schubert
434780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
435780fb4a2SCy Schubert "PKCS #12: Successfully decrypted PKCS8ShroudedKeyBag");
436780fb4a2SCy Schubert crypto_private_key_free(cred->key);
437780fb4a2SCy Schubert cred->key = key;
438780fb4a2SCy Schubert
439780fb4a2SCy Schubert return 0;
440780fb4a2SCy Schubert }
441780fb4a2SCy Schubert
442780fb4a2SCy Schubert
pkcs12_certbag(struct tlsv1_credentials * cred,const u8 * buf,size_t len)443780fb4a2SCy Schubert static int pkcs12_certbag(struct tlsv1_credentials *cred,
444780fb4a2SCy Schubert const u8 *buf, size_t len)
445780fb4a2SCy Schubert {
446780fb4a2SCy Schubert struct asn1_hdr hdr;
447780fb4a2SCy Schubert struct asn1_oid oid;
448780fb4a2SCy Schubert char obuf[80];
449780fb4a2SCy Schubert const u8 *pos, *end;
450780fb4a2SCy Schubert
451780fb4a2SCy Schubert /*
452780fb4a2SCy Schubert * CertBag ::= SEQUENCE {
453780fb4a2SCy Schubert * certId BAG-TYPE.&id ({CertTypes}),
454780fb4a2SCy Schubert * certValue [0] EXPLICIT BAG-TYPE.&Type ({CertTypes}{@certId})
455780fb4a2SCy Schubert * }
456780fb4a2SCy Schubert */
457780fb4a2SCy Schubert
458*c1d255d3SCy Schubert if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
459*c1d255d3SCy Schubert asn1_unexpected(&hdr, "PKCS #12: Expected SEQUENCE (CertBag)");
460780fb4a2SCy Schubert return -1;
461780fb4a2SCy Schubert }
462780fb4a2SCy Schubert
463780fb4a2SCy Schubert pos = hdr.payload;
464780fb4a2SCy Schubert end = hdr.payload + hdr.length;
465780fb4a2SCy Schubert
466780fb4a2SCy Schubert if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
467780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
468780fb4a2SCy Schubert "PKCS #12: Failed to parse OID (certId)");
469780fb4a2SCy Schubert return -1;
470780fb4a2SCy Schubert }
471780fb4a2SCy Schubert
472780fb4a2SCy Schubert asn1_oid_to_str(&oid, obuf, sizeof(obuf));
473780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "PKCS #12: certId %s", obuf);
474780fb4a2SCy Schubert
475780fb4a2SCy Schubert if (!is_oid_pkcs9_x509_cert(&oid)) {
476780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
477780fb4a2SCy Schubert "PKCS #12: Ignored unsupported certificate type (certId %s)",
478780fb4a2SCy Schubert obuf);
479780fb4a2SCy Schubert }
480780fb4a2SCy Schubert
481*c1d255d3SCy Schubert if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed ||
482*c1d255d3SCy Schubert !asn1_is_cs_tag(&hdr, 0)) {
483*c1d255d3SCy Schubert asn1_unexpected(&hdr,
484*c1d255d3SCy Schubert "PKCS #12: Expected [0] EXPLICIT (certValue)");
485780fb4a2SCy Schubert return -1;
486780fb4a2SCy Schubert }
487780fb4a2SCy Schubert
488780fb4a2SCy Schubert if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
489*c1d255d3SCy Schubert !asn1_is_octetstring(&hdr)) {
490*c1d255d3SCy Schubert asn1_unexpected(&hdr,
491*c1d255d3SCy Schubert "PKCS #12: Expected OCTET STRING (x509Certificate)");
492780fb4a2SCy Schubert return -1;
493780fb4a2SCy Schubert }
494780fb4a2SCy Schubert
495780fb4a2SCy Schubert wpa_hexdump(MSG_DEBUG, "PKCS #12: x509Certificate",
496780fb4a2SCy Schubert hdr.payload, hdr.length);
497780fb4a2SCy Schubert if (cred->cert) {
498780fb4a2SCy Schubert struct x509_certificate *cert;
499780fb4a2SCy Schubert
500780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "PKCS #12: Ignore extra certificate");
501780fb4a2SCy Schubert cert = x509_certificate_parse(hdr.payload, hdr.length);
502780fb4a2SCy Schubert if (!cert) {
503780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
504780fb4a2SCy Schubert "PKCS #12: Failed to parse x509Certificate");
505780fb4a2SCy Schubert return 0;
506780fb4a2SCy Schubert }
507780fb4a2SCy Schubert x509_certificate_chain_free(cert);
508780fb4a2SCy Schubert
509780fb4a2SCy Schubert return 0;
510780fb4a2SCy Schubert }
511780fb4a2SCy Schubert return tlsv1_set_cert(cred, NULL, hdr.payload, hdr.length);
512780fb4a2SCy Schubert }
513780fb4a2SCy Schubert
514780fb4a2SCy Schubert
pkcs12_parse_attr_friendly_name(const u8 * pos,const u8 * end)515780fb4a2SCy Schubert static int pkcs12_parse_attr_friendly_name(const u8 *pos, const u8 *end)
516780fb4a2SCy Schubert {
517780fb4a2SCy Schubert struct asn1_hdr hdr;
518780fb4a2SCy Schubert
519780fb4a2SCy Schubert /*
520780fb4a2SCy Schubert * RFC 2985, 5.5.1:
521780fb4a2SCy Schubert * friendlyName ATTRIBUTE ::= {
522780fb4a2SCy Schubert * WITH SYNTAX BMPString (SIZE(1..pkcs-9-ub-friendlyName))
523780fb4a2SCy Schubert * EQUALITY MATCHING RULE caseIgnoreMatch
524780fb4a2SCy Schubert * SINGLE VALUE TRUE
525780fb4a2SCy Schubert * ID pkcs-9-at-friendlyName
526780fb4a2SCy Schubert * }
527780fb4a2SCy Schubert */
528780fb4a2SCy Schubert if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
529*c1d255d3SCy Schubert !asn1_is_bmpstring(&hdr)) {
530*c1d255d3SCy Schubert asn1_unexpected(&hdr,
531*c1d255d3SCy Schubert "PKCS #12: Expected BMPSTRING (friendlyName)");
532780fb4a2SCy Schubert return 0;
533780fb4a2SCy Schubert }
534780fb4a2SCy Schubert wpa_hexdump_ascii(MSG_DEBUG, "PKCS #12: friendlyName",
535780fb4a2SCy Schubert hdr.payload, hdr.length);
536780fb4a2SCy Schubert return 0;
537780fb4a2SCy Schubert }
538780fb4a2SCy Schubert
539780fb4a2SCy Schubert
pkcs12_parse_attr_local_key_id(const u8 * pos,const u8 * end)540780fb4a2SCy Schubert static int pkcs12_parse_attr_local_key_id(const u8 *pos, const u8 *end)
541780fb4a2SCy Schubert {
542780fb4a2SCy Schubert struct asn1_hdr hdr;
543780fb4a2SCy Schubert
544780fb4a2SCy Schubert /*
545780fb4a2SCy Schubert * RFC 2985, 5.5.2:
546780fb4a2SCy Schubert * localKeyId ATTRIBUTE ::= {
547780fb4a2SCy Schubert * WITH SYNTAX OCTET STRING
548780fb4a2SCy Schubert * EQUALITY MATCHING RULE octetStringMatch
549780fb4a2SCy Schubert * SINGLE VALUE TRUE
550780fb4a2SCy Schubert * ID pkcs-9-at-localKeyId
551780fb4a2SCy Schubert * }
552780fb4a2SCy Schubert */
553780fb4a2SCy Schubert if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
554*c1d255d3SCy Schubert !asn1_is_octetstring(&hdr)) {
555*c1d255d3SCy Schubert asn1_unexpected(&hdr,
556*c1d255d3SCy Schubert "PKCS #12: Expected OCTET STRING (localKeyID)");
557780fb4a2SCy Schubert return -1;
558780fb4a2SCy Schubert }
559780fb4a2SCy Schubert wpa_hexdump_key(MSG_DEBUG, "PKCS #12: localKeyID",
560780fb4a2SCy Schubert hdr.payload, hdr.length);
561780fb4a2SCy Schubert return 0;
562780fb4a2SCy Schubert }
563780fb4a2SCy Schubert
564780fb4a2SCy Schubert
pkcs12_parse_attr(const u8 * pos,size_t len)565780fb4a2SCy Schubert static int pkcs12_parse_attr(const u8 *pos, size_t len)
566780fb4a2SCy Schubert {
567780fb4a2SCy Schubert const u8 *end = pos + len;
568780fb4a2SCy Schubert struct asn1_hdr hdr;
569780fb4a2SCy Schubert struct asn1_oid a_oid;
570780fb4a2SCy Schubert char obuf[80];
571780fb4a2SCy Schubert
572780fb4a2SCy Schubert /*
573780fb4a2SCy Schubert * PKCS12Attribute ::= SEQUENCE {
574780fb4a2SCy Schubert * attrId ATTRIBUTE.&id ({PKCS12AttrSet}),
575780fb4a2SCy Schubert * attrValues SET OF ATTRIBUTE.&Type ({PKCS12AttrSet}{@attrId})
576780fb4a2SCy Schubert * }
577780fb4a2SCy Schubert */
578780fb4a2SCy Schubert
579780fb4a2SCy Schubert if (asn1_get_oid(pos, end - pos, &a_oid, &pos)) {
580780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "PKCS #12: Failed to parse OID (attrId)");
581780fb4a2SCy Schubert return -1;
582780fb4a2SCy Schubert }
583780fb4a2SCy Schubert
584780fb4a2SCy Schubert asn1_oid_to_str(&a_oid, obuf, sizeof(obuf));
585780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "PKCS #12: attrId %s", obuf);
586780fb4a2SCy Schubert
587*c1d255d3SCy Schubert if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_set(&hdr)) {
588*c1d255d3SCy Schubert asn1_unexpected(&hdr, "PKCS #12: Expected SET (attrValues)");
589780fb4a2SCy Schubert return -1;
590780fb4a2SCy Schubert }
591780fb4a2SCy Schubert wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: attrValues",
592780fb4a2SCy Schubert hdr.payload, hdr.length);
593780fb4a2SCy Schubert pos = hdr.payload;
594780fb4a2SCy Schubert end = hdr.payload + hdr.length;
595780fb4a2SCy Schubert
596780fb4a2SCy Schubert if (is_oid_pkcs9_friendly_name(&a_oid))
597780fb4a2SCy Schubert return pkcs12_parse_attr_friendly_name(pos, end);
598780fb4a2SCy Schubert if (is_oid_pkcs9_local_key_id(&a_oid))
599780fb4a2SCy Schubert return pkcs12_parse_attr_local_key_id(pos, end);
600780fb4a2SCy Schubert
601780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "PKCS #12: Ignore unknown attribute");
602780fb4a2SCy Schubert return 0;
603780fb4a2SCy Schubert }
604780fb4a2SCy Schubert
605780fb4a2SCy Schubert
pkcs12_safebag(struct tlsv1_credentials * cred,const u8 * buf,size_t len,const char * passwd)606780fb4a2SCy Schubert static int pkcs12_safebag(struct tlsv1_credentials *cred,
607780fb4a2SCy Schubert const u8 *buf, size_t len, const char *passwd)
608780fb4a2SCy Schubert {
609780fb4a2SCy Schubert struct asn1_hdr hdr;
610780fb4a2SCy Schubert struct asn1_oid oid;
611780fb4a2SCy Schubert char obuf[80];
612780fb4a2SCy Schubert const u8 *pos = buf, *end = buf + len;
613780fb4a2SCy Schubert const u8 *value;
614780fb4a2SCy Schubert size_t value_len;
615780fb4a2SCy Schubert
616780fb4a2SCy Schubert wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: SafeBag", buf, len);
617780fb4a2SCy Schubert
618780fb4a2SCy Schubert /* BAG-TYPE ::= TYPE-IDENTIFIER */
619780fb4a2SCy Schubert if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
620780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
621780fb4a2SCy Schubert "PKCS #12: Failed to parse OID (BAG-TYPE)");
622780fb4a2SCy Schubert return -1;
623780fb4a2SCy Schubert }
624780fb4a2SCy Schubert
625780fb4a2SCy Schubert asn1_oid_to_str(&oid, obuf, sizeof(obuf));
626780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "PKCS #12: BAG-TYPE %s", obuf);
627780fb4a2SCy Schubert
628*c1d255d3SCy Schubert if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed ||
629*c1d255d3SCy Schubert !asn1_is_cs_tag(&hdr, 0)) {
630*c1d255d3SCy Schubert asn1_unexpected(&hdr,
631*c1d255d3SCy Schubert "PKCS #12: Expected [0] EXPLICIT (bagValue)");
632780fb4a2SCy Schubert return 0;
633780fb4a2SCy Schubert }
634780fb4a2SCy Schubert value = hdr.payload;
635780fb4a2SCy Schubert value_len = hdr.length;
636780fb4a2SCy Schubert wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: bagValue", value, value_len);
637780fb4a2SCy Schubert pos = hdr.payload + hdr.length;
638780fb4a2SCy Schubert
639780fb4a2SCy Schubert if (pos < end) {
640780fb4a2SCy Schubert /* bagAttributes SET OF PKCS12Attribute OPTIONAL */
641780fb4a2SCy Schubert if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
642*c1d255d3SCy Schubert !asn1_is_set(&hdr)) {
643*c1d255d3SCy Schubert asn1_unexpected(&hdr,
644*c1d255d3SCy Schubert "PKCS #12: Expected SET (bagAttributes)");
645780fb4a2SCy Schubert return -1;
646780fb4a2SCy Schubert }
647780fb4a2SCy Schubert wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: bagAttributes",
648780fb4a2SCy Schubert hdr.payload, hdr.length);
649780fb4a2SCy Schubert
650780fb4a2SCy Schubert pos = hdr.payload;
651780fb4a2SCy Schubert end = hdr.payload + hdr.length;
652780fb4a2SCy Schubert while (pos < end) {
653780fb4a2SCy Schubert /* PKCS12Attribute ::= SEQUENCE */
654780fb4a2SCy Schubert if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
655*c1d255d3SCy Schubert !asn1_is_sequence(&hdr)) {
656*c1d255d3SCy Schubert asn1_unexpected(&hdr,
657*c1d255d3SCy Schubert "PKCS #12: Expected SEQUENCE (PKCS12Attribute)");
658780fb4a2SCy Schubert return -1;
659780fb4a2SCy Schubert }
660780fb4a2SCy Schubert if (pkcs12_parse_attr(hdr.payload, hdr.length) < 0)
661780fb4a2SCy Schubert return -1;
662780fb4a2SCy Schubert pos = hdr.payload + hdr.length;
663780fb4a2SCy Schubert }
664780fb4a2SCy Schubert }
665780fb4a2SCy Schubert
666780fb4a2SCy Schubert if (pkcs12_is_bagtype_oid(&oid, 1))
667780fb4a2SCy Schubert return pkcs12_keybag(cred, value, value_len);
668780fb4a2SCy Schubert if (pkcs12_is_bagtype_oid(&oid, 2))
669780fb4a2SCy Schubert return pkcs12_pkcs8_keybag(cred, value, value_len, passwd);
670780fb4a2SCy Schubert if (pkcs12_is_bagtype_oid(&oid, 3))
671780fb4a2SCy Schubert return pkcs12_certbag(cred, value, value_len);
672780fb4a2SCy Schubert
673780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "PKCS #12: Ignore unsupported BAG-TYPE");
674780fb4a2SCy Schubert return 0;
675780fb4a2SCy Schubert }
676780fb4a2SCy Schubert
677780fb4a2SCy Schubert
pkcs12_safecontents(struct tlsv1_credentials * cred,const u8 * buf,size_t len,const char * passwd)678780fb4a2SCy Schubert static int pkcs12_safecontents(struct tlsv1_credentials *cred,
679780fb4a2SCy Schubert const u8 *buf, size_t len,
680780fb4a2SCy Schubert const char *passwd)
681780fb4a2SCy Schubert {
682780fb4a2SCy Schubert struct asn1_hdr hdr;
683780fb4a2SCy Schubert const u8 *pos, *end;
684780fb4a2SCy Schubert
685780fb4a2SCy Schubert /* SafeContents ::= SEQUENCE OF SafeBag */
686*c1d255d3SCy Schubert if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
687*c1d255d3SCy Schubert asn1_unexpected(&hdr,
688*c1d255d3SCy Schubert "PKCS #12: Expected SEQUENCE (SafeContents)");
689780fb4a2SCy Schubert return -1;
690780fb4a2SCy Schubert }
691780fb4a2SCy Schubert pos = hdr.payload;
692780fb4a2SCy Schubert end = hdr.payload + hdr.length;
693780fb4a2SCy Schubert
694780fb4a2SCy Schubert /*
695780fb4a2SCy Schubert * SafeBag ::= SEQUENCE {
696780fb4a2SCy Schubert * bagId BAG-TYPE.&id ({PKCS12BagSet})
697780fb4a2SCy Schubert * bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}),
698780fb4a2SCy Schubert * bagAttributes SET OF PKCS12Attribute OPTIONAL
699780fb4a2SCy Schubert * }
700780fb4a2SCy Schubert */
701780fb4a2SCy Schubert
702780fb4a2SCy Schubert while (pos < end) {
703780fb4a2SCy Schubert if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
704*c1d255d3SCy Schubert !asn1_is_sequence(&hdr)) {
705*c1d255d3SCy Schubert asn1_unexpected(&hdr,
706*c1d255d3SCy Schubert "PKCS #12: Expected SEQUENCE (SafeBag)");
707780fb4a2SCy Schubert return -1;
708780fb4a2SCy Schubert }
709780fb4a2SCy Schubert if (pkcs12_safebag(cred, hdr.payload, hdr.length, passwd) < 0)
710780fb4a2SCy Schubert return -1;
711780fb4a2SCy Schubert pos = hdr.payload + hdr.length;
712780fb4a2SCy Schubert }
713780fb4a2SCy Schubert
714780fb4a2SCy Schubert return 0;
715780fb4a2SCy Schubert }
716780fb4a2SCy Schubert
717780fb4a2SCy Schubert
pkcs12_parse_content_data(struct tlsv1_credentials * cred,const u8 * pos,const u8 * end,const char * passwd)718780fb4a2SCy Schubert static int pkcs12_parse_content_data(struct tlsv1_credentials *cred,
719780fb4a2SCy Schubert const u8 *pos, const u8 *end,
720780fb4a2SCy Schubert const char *passwd)
721780fb4a2SCy Schubert {
722780fb4a2SCy Schubert struct asn1_hdr hdr;
723780fb4a2SCy Schubert
724780fb4a2SCy Schubert /* Data ::= OCTET STRING */
725780fb4a2SCy Schubert if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
726*c1d255d3SCy Schubert !asn1_is_octetstring(&hdr)) {
727*c1d255d3SCy Schubert asn1_unexpected(&hdr, "PKCS #12: Expected OCTET STRING (Data)");
728780fb4a2SCy Schubert return -1;
729780fb4a2SCy Schubert }
730780fb4a2SCy Schubert
731780fb4a2SCy Schubert wpa_hexdump(MSG_MSGDUMP, "PKCS #12: Data", hdr.payload, hdr.length);
732780fb4a2SCy Schubert
733780fb4a2SCy Schubert return pkcs12_safecontents(cred, hdr.payload, hdr.length, passwd);
734780fb4a2SCy Schubert }
735780fb4a2SCy Schubert
736780fb4a2SCy Schubert
pkcs12_parse_content_enc_data(struct tlsv1_credentials * cred,const u8 * pos,const u8 * end,const char * passwd)737780fb4a2SCy Schubert static int pkcs12_parse_content_enc_data(struct tlsv1_credentials *cred,
738780fb4a2SCy Schubert const u8 *pos, const u8 *end,
739780fb4a2SCy Schubert const char *passwd)
740780fb4a2SCy Schubert {
741780fb4a2SCy Schubert struct asn1_hdr hdr;
742780fb4a2SCy Schubert struct asn1_oid oid;
743780fb4a2SCy Schubert char buf[80];
744780fb4a2SCy Schubert const u8 *enc_alg;
745780fb4a2SCy Schubert u8 *data;
746780fb4a2SCy Schubert size_t enc_alg_len, data_len;
747780fb4a2SCy Schubert int res = -1;
748780fb4a2SCy Schubert
749780fb4a2SCy Schubert /*
750780fb4a2SCy Schubert * EncryptedData ::= SEQUENCE {
751780fb4a2SCy Schubert * version Version,
752780fb4a2SCy Schubert * encryptedContentInfo EncryptedContentInfo }
753780fb4a2SCy Schubert */
754780fb4a2SCy Schubert if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
755*c1d255d3SCy Schubert !asn1_is_sequence(&hdr)) {
756*c1d255d3SCy Schubert asn1_unexpected(&hdr,
757*c1d255d3SCy Schubert "PKCS #12: Expected SEQUENCE (EncryptedData)");
758780fb4a2SCy Schubert return 0;
759780fb4a2SCy Schubert }
760780fb4a2SCy Schubert pos = hdr.payload;
761780fb4a2SCy Schubert
762780fb4a2SCy Schubert /* Version ::= INTEGER */
763*c1d255d3SCy Schubert if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_integer(&hdr)) {
764*c1d255d3SCy Schubert asn1_unexpected(&hdr,
765*c1d255d3SCy Schubert "PKCS #12: No INTEGER tag found for version");
766780fb4a2SCy Schubert return -1;
767780fb4a2SCy Schubert }
768780fb4a2SCy Schubert if (hdr.length != 1 || hdr.payload[0] != 0) {
769780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "PKCS #12: Unrecognized PKCS #7 version");
770780fb4a2SCy Schubert return -1;
771780fb4a2SCy Schubert }
772780fb4a2SCy Schubert pos = hdr.payload + hdr.length;
773780fb4a2SCy Schubert
774780fb4a2SCy Schubert wpa_hexdump(MSG_MSGDUMP, "PKCS #12: EncryptedContentInfo",
775780fb4a2SCy Schubert pos, end - pos);
776780fb4a2SCy Schubert
777780fb4a2SCy Schubert /*
778780fb4a2SCy Schubert * EncryptedContentInfo ::= SEQUENCE {
779780fb4a2SCy Schubert * contentType ContentType,
780780fb4a2SCy Schubert * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
781780fb4a2SCy Schubert * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL }
782780fb4a2SCy Schubert */
783780fb4a2SCy Schubert if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
784*c1d255d3SCy Schubert !asn1_is_sequence(&hdr)) {
785*c1d255d3SCy Schubert asn1_unexpected(&hdr,
786*c1d255d3SCy Schubert "PKCS #12: Expected SEQUENCE (EncryptedContentInfo)");
787780fb4a2SCy Schubert return -1;
788780fb4a2SCy Schubert }
789780fb4a2SCy Schubert
790780fb4a2SCy Schubert pos = hdr.payload;
791780fb4a2SCy Schubert end = pos + hdr.length;
792780fb4a2SCy Schubert
793780fb4a2SCy Schubert /* ContentType ::= OBJECT IDENTIFIER */
794780fb4a2SCy Schubert if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
795780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
796780fb4a2SCy Schubert "PKCS #12: Could not find OBJECT IDENTIFIER (contentType)");
797780fb4a2SCy Schubert return -1;
798780fb4a2SCy Schubert }
799780fb4a2SCy Schubert asn1_oid_to_str(&oid, buf, sizeof(buf));
800780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "PKCS #12: EncryptedContentInfo::contentType %s",
801780fb4a2SCy Schubert buf);
802780fb4a2SCy Schubert
803780fb4a2SCy Schubert if (!is_oid_pkcs7_data(&oid)) {
804780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
805780fb4a2SCy Schubert "PKCS #12: Unsupported EncryptedContentInfo::contentType %s",
806780fb4a2SCy Schubert buf);
807780fb4a2SCy Schubert return 0;
808780fb4a2SCy Schubert }
809780fb4a2SCy Schubert
810780fb4a2SCy Schubert /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
811780fb4a2SCy Schubert if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
812*c1d255d3SCy Schubert !asn1_is_sequence(&hdr)) {
813*c1d255d3SCy Schubert asn1_unexpected(&hdr,
814*c1d255d3SCy Schubert "PKCS #12: Expected SEQUENCE (ContentEncryptionAlgorithmIdentifier)");
815780fb4a2SCy Schubert return -1;
816780fb4a2SCy Schubert }
817780fb4a2SCy Schubert enc_alg = hdr.payload;
818780fb4a2SCy Schubert enc_alg_len = hdr.length;
819780fb4a2SCy Schubert pos = hdr.payload + hdr.length;
820780fb4a2SCy Schubert
821*c1d255d3SCy Schubert if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.constructed ||
822*c1d255d3SCy Schubert !asn1_is_cs_tag(&hdr, 0)) {
823*c1d255d3SCy Schubert asn1_unexpected(&hdr,
824*c1d255d3SCy Schubert "PKCS #12: Expected [0] IMPLICIT (encryptedContent)");
825780fb4a2SCy Schubert return -1;
826780fb4a2SCy Schubert }
827780fb4a2SCy Schubert
828780fb4a2SCy Schubert /* EncryptedContent ::= OCTET STRING */
829780fb4a2SCy Schubert data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length,
830780fb4a2SCy Schubert passwd, &data_len);
831780fb4a2SCy Schubert if (data) {
832780fb4a2SCy Schubert wpa_hexdump_key(MSG_MSGDUMP,
833780fb4a2SCy Schubert "PKCS #12: Decrypted encryptedContent",
834780fb4a2SCy Schubert data, data_len);
835780fb4a2SCy Schubert res = pkcs12_safecontents(cred, data, data_len, passwd);
836780fb4a2SCy Schubert os_free(data);
837780fb4a2SCy Schubert }
838780fb4a2SCy Schubert
839780fb4a2SCy Schubert return res;
840780fb4a2SCy Schubert }
841780fb4a2SCy Schubert
842780fb4a2SCy Schubert
pkcs12_parse_content(struct tlsv1_credentials * cred,const u8 * buf,size_t len,const char * passwd)843780fb4a2SCy Schubert static int pkcs12_parse_content(struct tlsv1_credentials *cred,
844780fb4a2SCy Schubert const u8 *buf, size_t len,
845780fb4a2SCy Schubert const char *passwd)
846780fb4a2SCy Schubert {
847780fb4a2SCy Schubert const u8 *pos = buf;
848780fb4a2SCy Schubert const u8 *end = buf + len;
849780fb4a2SCy Schubert struct asn1_oid oid;
850780fb4a2SCy Schubert char txt[80];
851780fb4a2SCy Schubert struct asn1_hdr hdr;
852780fb4a2SCy Schubert
853780fb4a2SCy Schubert wpa_hexdump(MSG_MSGDUMP, "PKCS #12: ContentInfo", buf, len);
854780fb4a2SCy Schubert
855780fb4a2SCy Schubert if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
856780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
857780fb4a2SCy Schubert "PKCS #12: Could not find OBJECT IDENTIFIER (contentType)");
858780fb4a2SCy Schubert return 0;
859780fb4a2SCy Schubert }
860780fb4a2SCy Schubert
861780fb4a2SCy Schubert asn1_oid_to_str(&oid, txt, sizeof(txt));
862780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "PKCS #12: contentType %s", txt);
863780fb4a2SCy Schubert
864*c1d255d3SCy Schubert if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed ||
865*c1d255d3SCy Schubert !asn1_is_cs_tag(&hdr, 0)) {
866*c1d255d3SCy Schubert asn1_unexpected(&hdr,
867*c1d255d3SCy Schubert "PKCS #12: Expected [0] EXPLICIT (content)");
868780fb4a2SCy Schubert return 0;
869780fb4a2SCy Schubert }
870780fb4a2SCy Schubert pos = hdr.payload;
871780fb4a2SCy Schubert
872780fb4a2SCy Schubert if (is_oid_pkcs7_data(&oid))
873780fb4a2SCy Schubert return pkcs12_parse_content_data(cred, pos, end, passwd);
874780fb4a2SCy Schubert if (is_oid_pkcs7_enc_data(&oid))
875780fb4a2SCy Schubert return pkcs12_parse_content_enc_data(cred, pos, end, passwd);
876780fb4a2SCy Schubert
877780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "PKCS #12: Ignored unsupported contentType %s",
878780fb4a2SCy Schubert txt);
879780fb4a2SCy Schubert
880780fb4a2SCy Schubert return 0;
881780fb4a2SCy Schubert }
882780fb4a2SCy Schubert
883780fb4a2SCy Schubert
pkcs12_parse(struct tlsv1_credentials * cred,const u8 * key,size_t len,const char * passwd)884780fb4a2SCy Schubert static int pkcs12_parse(struct tlsv1_credentials *cred,
885780fb4a2SCy Schubert const u8 *key, size_t len, const char *passwd)
886780fb4a2SCy Schubert {
887780fb4a2SCy Schubert struct asn1_hdr hdr;
888780fb4a2SCy Schubert const u8 *pos, *end;
889780fb4a2SCy Schubert struct asn1_oid oid;
890780fb4a2SCy Schubert char buf[80];
891780fb4a2SCy Schubert
892780fb4a2SCy Schubert /*
893780fb4a2SCy Schubert * PFX ::= SEQUENCE {
894780fb4a2SCy Schubert * version INTEGER {v3(3)}(v3,...),
895780fb4a2SCy Schubert * authSafe ContentInfo,
896780fb4a2SCy Schubert * macData MacData OPTIONAL
897780fb4a2SCy Schubert * }
898780fb4a2SCy Schubert */
899780fb4a2SCy Schubert
900*c1d255d3SCy Schubert if (asn1_get_next(key, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
901*c1d255d3SCy Schubert asn1_unexpected(&hdr,
902*c1d255d3SCy Schubert "PKCS #12: Expected SEQUENCE (PFX); assume PKCS #12 not used");
903780fb4a2SCy Schubert return -1;
904780fb4a2SCy Schubert }
905780fb4a2SCy Schubert
906780fb4a2SCy Schubert pos = hdr.payload;
907780fb4a2SCy Schubert end = pos + hdr.length;
908780fb4a2SCy Schubert
909*c1d255d3SCy Schubert if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_integer(&hdr)) {
910*c1d255d3SCy Schubert asn1_unexpected(&hdr,
911*c1d255d3SCy Schubert "PKCS #12: No INTEGER tag found for version");
912780fb4a2SCy Schubert return -1;
913780fb4a2SCy Schubert }
914780fb4a2SCy Schubert if (hdr.length != 1 || hdr.payload[0] != 3) {
915780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "PKCS #12: Unrecognized version");
916780fb4a2SCy Schubert return -1;
917780fb4a2SCy Schubert }
918780fb4a2SCy Schubert pos = hdr.payload + hdr.length;
919780fb4a2SCy Schubert
920780fb4a2SCy Schubert /*
921780fb4a2SCy Schubert * ContentInfo ::= SEQUENCE {
922780fb4a2SCy Schubert * contentType ContentType,
923780fb4a2SCy Schubert * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
924780fb4a2SCy Schubert */
925780fb4a2SCy Schubert
926780fb4a2SCy Schubert if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
927*c1d255d3SCy Schubert !asn1_is_sequence(&hdr)) {
928*c1d255d3SCy Schubert asn1_unexpected(&hdr,
929*c1d255d3SCy Schubert "PKCS #12: Expected SEQUENCE (authSafe); assume PKCS #12 not used");
930780fb4a2SCy Schubert return -1;
931780fb4a2SCy Schubert }
932780fb4a2SCy Schubert
933780fb4a2SCy Schubert pos = hdr.payload;
934780fb4a2SCy Schubert end = pos + hdr.length;
935780fb4a2SCy Schubert
936780fb4a2SCy Schubert /* ContentType ::= OBJECT IDENTIFIER */
937780fb4a2SCy Schubert if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
938780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
939780fb4a2SCy Schubert "PKCS #12: Could not find OBJECT IDENTIFIER (contentType); assume PKCS #12 not used");
940780fb4a2SCy Schubert return -1;
941780fb4a2SCy Schubert }
942780fb4a2SCy Schubert asn1_oid_to_str(&oid, buf, sizeof(buf));
943780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "PKCS #12: contentType %s", buf);
944780fb4a2SCy Schubert if (!is_oid_pkcs7_data(&oid)) {
945780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "PKCS #12: Unsupported contentType %s",
946780fb4a2SCy Schubert buf);
947780fb4a2SCy Schubert return -1;
948780fb4a2SCy Schubert }
949780fb4a2SCy Schubert
950*c1d255d3SCy Schubert if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed ||
951*c1d255d3SCy Schubert !asn1_is_cs_tag(&hdr, 0)) {
952*c1d255d3SCy Schubert asn1_unexpected(&hdr,
953*c1d255d3SCy Schubert "PKCS #12: Expected [0] EXPLICIT (content); assume PKCS #12 not used");
954780fb4a2SCy Schubert return -1;
955780fb4a2SCy Schubert }
956780fb4a2SCy Schubert
957780fb4a2SCy Schubert pos = hdr.payload;
958780fb4a2SCy Schubert
959780fb4a2SCy Schubert /* Data ::= OCTET STRING */
960780fb4a2SCy Schubert if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
961*c1d255d3SCy Schubert !asn1_is_octetstring(&hdr)) {
962*c1d255d3SCy Schubert asn1_unexpected(&hdr,
963*c1d255d3SCy Schubert "PKCS #12: Expected OCTET STRING (Data); assume PKCS #12 not used");
964780fb4a2SCy Schubert return -1;
965780fb4a2SCy Schubert }
966780fb4a2SCy Schubert
967780fb4a2SCy Schubert /*
968780fb4a2SCy Schubert * AuthenticatedSafe ::= SEQUENCE OF ContentInfo
969780fb4a2SCy Schubert * -- Data if unencrypted
970780fb4a2SCy Schubert * -- EncryptedData if password-encrypted
971780fb4a2SCy Schubert * -- EnvelopedData if public key-encrypted
972780fb4a2SCy Schubert */
973780fb4a2SCy Schubert wpa_hexdump(MSG_MSGDUMP, "PKCS #12: Data content",
974780fb4a2SCy Schubert hdr.payload, hdr.length);
975780fb4a2SCy Schubert
976780fb4a2SCy Schubert if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
977*c1d255d3SCy Schubert !asn1_is_sequence(&hdr)) {
978*c1d255d3SCy Schubert asn1_unexpected(&hdr,
979*c1d255d3SCy Schubert "PKCS #12: Expected SEQUENCE within Data content; assume PKCS #12 not used");
980780fb4a2SCy Schubert return -1;
981780fb4a2SCy Schubert }
982780fb4a2SCy Schubert
983780fb4a2SCy Schubert pos = hdr.payload;
984780fb4a2SCy Schubert end = pos + hdr.length;
985780fb4a2SCy Schubert
986780fb4a2SCy Schubert while (end > pos) {
987780fb4a2SCy Schubert if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
988*c1d255d3SCy Schubert !asn1_is_sequence(&hdr)) {
989*c1d255d3SCy Schubert asn1_unexpected(&hdr,
990*c1d255d3SCy Schubert "PKCS #12: Expected SEQUENCE (ContentInfo); assume PKCS #12 not used");
991780fb4a2SCy Schubert return -1;
992780fb4a2SCy Schubert }
993780fb4a2SCy Schubert if (pkcs12_parse_content(cred, hdr.payload, hdr.length,
994780fb4a2SCy Schubert passwd) < 0)
995780fb4a2SCy Schubert return -1;
996780fb4a2SCy Schubert
997780fb4a2SCy Schubert pos = hdr.payload + hdr.length;
998780fb4a2SCy Schubert }
999780fb4a2SCy Schubert
1000780fb4a2SCy Schubert return 0;
1001780fb4a2SCy Schubert }
1002780fb4a2SCy Schubert
1003780fb4a2SCy Schubert #endif /* PKCS12_FUNCS */
1004780fb4a2SCy Schubert
1005780fb4a2SCy Schubert
tlsv1_set_key(struct tlsv1_credentials * cred,const u8 * key,size_t len,const char * passwd)1006e28a4053SRui Paulo static int tlsv1_set_key(struct tlsv1_credentials *cred,
1007e28a4053SRui Paulo const u8 *key, size_t len, const char *passwd)
1008e28a4053SRui Paulo {
1009e28a4053SRui Paulo cred->key = crypto_private_key_import(key, len, passwd);
1010e28a4053SRui Paulo if (cred->key == NULL)
1011e28a4053SRui Paulo cred->key = tlsv1_set_key_pem(key, len);
1012e28a4053SRui Paulo if (cred->key == NULL)
1013e28a4053SRui Paulo cred->key = tlsv1_set_key_enc_pem(key, len, passwd);
1014780fb4a2SCy Schubert #ifdef PKCS12_FUNCS
1015780fb4a2SCy Schubert if (!cred->key)
1016780fb4a2SCy Schubert pkcs12_parse(cred, key, len, passwd);
1017780fb4a2SCy Schubert #endif /* PKCS12_FUNCS */
101839beb93cSSam Leffler if (cred->key == NULL) {
101939beb93cSSam Leffler wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
102039beb93cSSam Leffler return -1;
102139beb93cSSam Leffler }
102239beb93cSSam Leffler return 0;
102339beb93cSSam Leffler }
102439beb93cSSam Leffler
102539beb93cSSam Leffler
102639beb93cSSam Leffler /**
102739beb93cSSam Leffler * tlsv1_set_private_key - Set private key
102839beb93cSSam Leffler * @cred: TLSv1 credentials from tlsv1_cred_alloc()
102939beb93cSSam Leffler * @private_key: File or reference name for the key in PEM or DER format
103039beb93cSSam Leffler * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
103139beb93cSSam Leffler * passphrase is used.
103239beb93cSSam Leffler * @private_key_blob: private_key as inlined data or %NULL if not used
103339beb93cSSam Leffler * @private_key_blob_len: private_key_blob length
103439beb93cSSam Leffler * Returns: 0 on success, -1 on failure
103539beb93cSSam Leffler */
tlsv1_set_private_key(struct tlsv1_credentials * cred,const char * private_key,const char * private_key_passwd,const u8 * private_key_blob,size_t private_key_blob_len)103639beb93cSSam Leffler int tlsv1_set_private_key(struct tlsv1_credentials *cred,
103739beb93cSSam Leffler const char *private_key,
103839beb93cSSam Leffler const char *private_key_passwd,
103939beb93cSSam Leffler const u8 *private_key_blob,
104039beb93cSSam Leffler size_t private_key_blob_len)
104139beb93cSSam Leffler {
104239beb93cSSam Leffler crypto_private_key_free(cred->key);
104339beb93cSSam Leffler cred->key = NULL;
104439beb93cSSam Leffler
104539beb93cSSam Leffler if (private_key_blob)
104639beb93cSSam Leffler return tlsv1_set_key(cred, private_key_blob,
1047e28a4053SRui Paulo private_key_blob_len,
1048e28a4053SRui Paulo private_key_passwd);
104939beb93cSSam Leffler
105039beb93cSSam Leffler if (private_key) {
105139beb93cSSam Leffler u8 *buf;
105239beb93cSSam Leffler size_t len;
105339beb93cSSam Leffler int ret;
105439beb93cSSam Leffler
105539beb93cSSam Leffler buf = (u8 *) os_readfile(private_key, &len);
105639beb93cSSam Leffler if (buf == NULL) {
105739beb93cSSam Leffler wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
105839beb93cSSam Leffler private_key);
105939beb93cSSam Leffler return -1;
106039beb93cSSam Leffler }
106139beb93cSSam Leffler
1062e28a4053SRui Paulo ret = tlsv1_set_key(cred, buf, len, private_key_passwd);
106339beb93cSSam Leffler os_free(buf);
106439beb93cSSam Leffler return ret;
106539beb93cSSam Leffler }
106639beb93cSSam Leffler
106739beb93cSSam Leffler return 0;
106839beb93cSSam Leffler }
106939beb93cSSam Leffler
107039beb93cSSam Leffler
tlsv1_set_dhparams_der(struct tlsv1_credentials * cred,const u8 * dh,size_t len)107139beb93cSSam Leffler static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
107239beb93cSSam Leffler const u8 *dh, size_t len)
107339beb93cSSam Leffler {
107439beb93cSSam Leffler struct asn1_hdr hdr;
107539beb93cSSam Leffler const u8 *pos, *end;
107639beb93cSSam Leffler
107739beb93cSSam Leffler pos = dh;
107839beb93cSSam Leffler end = dh + len;
107939beb93cSSam Leffler
108039beb93cSSam Leffler /*
108139beb93cSSam Leffler * DHParameter ::= SEQUENCE {
108239beb93cSSam Leffler * prime INTEGER, -- p
108339beb93cSSam Leffler * base INTEGER, -- g
108439beb93cSSam Leffler * privateValueLength INTEGER OPTIONAL }
108539beb93cSSam Leffler */
108639beb93cSSam Leffler
108739beb93cSSam Leffler /* DHParamer ::= SEQUENCE */
1088*c1d255d3SCy Schubert if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
1089*c1d255d3SCy Schubert asn1_unexpected(&hdr,
1090*c1d255d3SCy Schubert "DH: DH parameters did not start with a valid SEQUENCE");
109139beb93cSSam Leffler return -1;
109239beb93cSSam Leffler }
109339beb93cSSam Leffler pos = hdr.payload;
109439beb93cSSam Leffler
109539beb93cSSam Leffler /* prime INTEGER */
1096*c1d255d3SCy Schubert if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1097*c1d255d3SCy Schubert !asn1_is_integer(&hdr)) {
1098*c1d255d3SCy Schubert asn1_unexpected(&hdr, "DH: No INTEGER tag found for p");
109939beb93cSSam Leffler return -1;
110039beb93cSSam Leffler }
110139beb93cSSam Leffler
110239beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "DH: prime (p)", hdr.payload, hdr.length);
110339beb93cSSam Leffler if (hdr.length == 0)
110439beb93cSSam Leffler return -1;
110539beb93cSSam Leffler os_free(cred->dh_p);
110685732ac8SCy Schubert cred->dh_p = os_memdup(hdr.payload, hdr.length);
110739beb93cSSam Leffler if (cred->dh_p == NULL)
110839beb93cSSam Leffler return -1;
110939beb93cSSam Leffler cred->dh_p_len = hdr.length;
111039beb93cSSam Leffler pos = hdr.payload + hdr.length;
111139beb93cSSam Leffler
111239beb93cSSam Leffler /* base INTEGER */
1113*c1d255d3SCy Schubert if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1114*c1d255d3SCy Schubert !asn1_is_integer(&hdr)) {
1115*c1d255d3SCy Schubert asn1_unexpected(&hdr, "DH: No INTEGER tag found for g");
111639beb93cSSam Leffler return -1;
111739beb93cSSam Leffler }
111839beb93cSSam Leffler
111939beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "DH: base (g)", hdr.payload, hdr.length);
112039beb93cSSam Leffler if (hdr.length == 0)
112139beb93cSSam Leffler return -1;
112239beb93cSSam Leffler os_free(cred->dh_g);
112385732ac8SCy Schubert cred->dh_g = os_memdup(hdr.payload, hdr.length);
112439beb93cSSam Leffler if (cred->dh_g == NULL)
112539beb93cSSam Leffler return -1;
112639beb93cSSam Leffler cred->dh_g_len = hdr.length;
112739beb93cSSam Leffler
112839beb93cSSam Leffler return 0;
112939beb93cSSam Leffler }
113039beb93cSSam Leffler
113139beb93cSSam Leffler
113239beb93cSSam Leffler static const char *pem_dhparams_begin = "-----BEGIN DH PARAMETERS-----";
113339beb93cSSam Leffler static const char *pem_dhparams_end = "-----END DH PARAMETERS-----";
113439beb93cSSam Leffler
113539beb93cSSam Leffler
tlsv1_set_dhparams_blob(struct tlsv1_credentials * cred,const u8 * buf,size_t len)113639beb93cSSam Leffler static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred,
113739beb93cSSam Leffler const u8 *buf, size_t len)
113839beb93cSSam Leffler {
113939beb93cSSam Leffler const u8 *pos, *end;
114039beb93cSSam Leffler unsigned char *der;
114139beb93cSSam Leffler size_t der_len;
114239beb93cSSam Leffler
114339beb93cSSam Leffler pos = search_tag(pem_dhparams_begin, buf, len);
114439beb93cSSam Leffler if (!pos) {
114539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: No PEM dhparams tag found - "
114639beb93cSSam Leffler "assume DER format");
114739beb93cSSam Leffler return tlsv1_set_dhparams_der(cred, buf, len);
114839beb93cSSam Leffler }
114939beb93cSSam Leffler
115039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format dhparams into DER "
115139beb93cSSam Leffler "format");
115239beb93cSSam Leffler
115339beb93cSSam Leffler pos += os_strlen(pem_dhparams_begin);
115439beb93cSSam Leffler end = search_tag(pem_dhparams_end, pos, buf + len - pos);
115539beb93cSSam Leffler if (end == NULL) {
115639beb93cSSam Leffler wpa_printf(MSG_INFO, "TLSv1: Could not find PEM dhparams end "
115739beb93cSSam Leffler "tag (%s)", pem_dhparams_end);
115839beb93cSSam Leffler return -1;
115939beb93cSSam Leffler }
116039beb93cSSam Leffler
1161*c1d255d3SCy Schubert der = base64_decode((const char *) pos, end - pos, &der_len);
116239beb93cSSam Leffler if (der == NULL) {
116339beb93cSSam Leffler wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams");
116439beb93cSSam Leffler return -1;
116539beb93cSSam Leffler }
116639beb93cSSam Leffler
116739beb93cSSam Leffler if (tlsv1_set_dhparams_der(cred, der, der_len) < 0) {
116839beb93cSSam Leffler wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM dhparams "
116939beb93cSSam Leffler "DER conversion");
117039beb93cSSam Leffler os_free(der);
117139beb93cSSam Leffler return -1;
117239beb93cSSam Leffler }
117339beb93cSSam Leffler
117439beb93cSSam Leffler os_free(der);
117539beb93cSSam Leffler
117639beb93cSSam Leffler return 0;
117739beb93cSSam Leffler }
117839beb93cSSam Leffler
117939beb93cSSam Leffler
118039beb93cSSam Leffler /**
118139beb93cSSam Leffler * tlsv1_set_dhparams - Set Diffie-Hellman parameters
118239beb93cSSam Leffler * @cred: TLSv1 credentials from tlsv1_cred_alloc()
118339beb93cSSam Leffler * @dh_file: File or reference name for the DH params in PEM or DER format
118439beb93cSSam Leffler * @dh_blob: DH params as inlined data or %NULL if not used
118539beb93cSSam Leffler * @dh_blob_len: dh_blob length
118639beb93cSSam Leffler * Returns: 0 on success, -1 on failure
118739beb93cSSam Leffler */
tlsv1_set_dhparams(struct tlsv1_credentials * cred,const char * dh_file,const u8 * dh_blob,size_t dh_blob_len)118839beb93cSSam Leffler int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,
118939beb93cSSam Leffler const u8 *dh_blob, size_t dh_blob_len)
119039beb93cSSam Leffler {
119139beb93cSSam Leffler if (dh_blob)
119239beb93cSSam Leffler return tlsv1_set_dhparams_blob(cred, dh_blob, dh_blob_len);
119339beb93cSSam Leffler
119439beb93cSSam Leffler if (dh_file) {
119539beb93cSSam Leffler u8 *buf;
119639beb93cSSam Leffler size_t len;
119739beb93cSSam Leffler int ret;
119839beb93cSSam Leffler
119939beb93cSSam Leffler buf = (u8 *) os_readfile(dh_file, &len);
120039beb93cSSam Leffler if (buf == NULL) {
120139beb93cSSam Leffler wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
120239beb93cSSam Leffler dh_file);
120339beb93cSSam Leffler return -1;
120439beb93cSSam Leffler }
120539beb93cSSam Leffler
120639beb93cSSam Leffler ret = tlsv1_set_dhparams_blob(cred, buf, len);
120739beb93cSSam Leffler os_free(buf);
120839beb93cSSam Leffler return ret;
120939beb93cSSam Leffler }
121039beb93cSSam Leffler
121139beb93cSSam Leffler return 0;
121239beb93cSSam Leffler }
1213