xref: /freebsd/contrib/wpa/src/tls/pkcs8.c (revision ba7319e9091b4f6ef15a9c4be3d3d076f3047f72)
1 /*
2  * PKCS #8 (Private-key information syntax)
3  * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "includes.h"
10 
11 #include "common.h"
12 #include "asn1.h"
13 #include "bignum.h"
14 #include "rsa.h"
15 #include "pkcs5.h"
16 #include "pkcs8.h"
17 
18 
19 struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len)
20 {
21 	struct asn1_hdr hdr;
22 	const u8 *pos, *end;
23 	struct bignum *zero;
24 	struct asn1_oid oid;
25 	char obuf[80];
26 
27 	/* PKCS #8, Chapter 6 */
28 
29 	/* PrivateKeyInfo ::= SEQUENCE */
30 	if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
31 		asn1_unexpected(&hdr,
32 				"PKCS #8: Does not start with PKCS #8 header (SEQUENCE)");
33 		return NULL;
34 	}
35 	pos = hdr.payload;
36 	end = pos + hdr.length;
37 
38 	/* version Version (Version ::= INTEGER) */
39 	if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_integer(&hdr)) {
40 		asn1_unexpected(&hdr, "PKCS #8: Expected INTEGER");
41 		return NULL;
42 	}
43 
44 	zero = bignum_init();
45 	if (zero == NULL)
46 		return NULL;
47 
48 	if (bignum_set_unsigned_bin(zero, hdr.payload, hdr.length) < 0) {
49 		wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse INTEGER");
50 		bignum_deinit(zero);
51 		return NULL;
52 	}
53 	pos = hdr.payload + hdr.length;
54 
55 	if (bignum_cmp_d(zero, 0) != 0) {
56 		wpa_printf(MSG_DEBUG, "PKCS #8: Expected zero INTEGER in the "
57 			   "beginning of private key; not found; assume "
58 			   "PKCS #8 not used");
59 		bignum_deinit(zero);
60 		return NULL;
61 	}
62 	bignum_deinit(zero);
63 
64 	/* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier
65 	 * (PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier) */
66 	if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
67 		asn1_unexpected(&hdr,
68 				"PKCS #8: Expected SEQUENCE (AlgorithmIdentifier); assume PKCS #8 not used");
69 		return NULL;
70 	}
71 
72 	if (asn1_get_oid(hdr.payload, hdr.length, &oid, &pos)) {
73 		wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse OID "
74 			   "(algorithm); assume PKCS #8 not used");
75 		return NULL;
76 	}
77 
78 	asn1_oid_to_str(&oid, obuf, sizeof(obuf));
79 	wpa_printf(MSG_DEBUG, "PKCS #8: algorithm=%s", obuf);
80 
81 	if (oid.len != 7 ||
82 	    oid.oid[0] != 1 /* iso */ ||
83 	    oid.oid[1] != 2 /* member-body */ ||
84 	    oid.oid[2] != 840 /* us */ ||
85 	    oid.oid[3] != 113549 /* rsadsi */ ||
86 	    oid.oid[4] != 1 /* pkcs */ ||
87 	    oid.oid[5] != 1 /* pkcs-1 */ ||
88 	    oid.oid[6] != 1 /* rsaEncryption */) {
89 		wpa_printf(MSG_DEBUG, "PKCS #8: Unsupported private key "
90 			   "algorithm %s", obuf);
91 		return NULL;
92 	}
93 
94 	pos = hdr.payload + hdr.length;
95 
96 	/* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */
97 	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
98 	    !asn1_is_octetstring(&hdr)) {
99 		asn1_unexpected(&hdr,
100 				"PKCS #8: Expected OCTETSTRING (privateKey)");
101 		return NULL;
102 	}
103 	wpa_printf(MSG_DEBUG, "PKCS #8: Try to parse RSAPrivateKey");
104 
105 	return (struct crypto_private_key *)
106 		crypto_rsa_import_private_key(hdr.payload, hdr.length);
107 }
108 
109 
110 struct crypto_private_key *
111 pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd)
112 {
113 	struct asn1_hdr hdr;
114 	const u8 *pos, *end, *enc_alg;
115 	size_t enc_alg_len;
116 	u8 *data;
117 	size_t data_len;
118 
119 	if (passwd == NULL)
120 		return NULL;
121 
122 	/*
123 	 * PKCS #8, Chapter 7
124 	 * EncryptedPrivateKeyInfo ::= SEQUENCE {
125 	 *   encryptionAlgorithm EncryptionAlgorithmIdentifier,
126 	 *   encryptedData EncryptedData }
127 	 * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
128 	 * EncryptedData ::= OCTET STRING
129 	 */
130 
131 	if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
132 		asn1_unexpected(&hdr,
133 				"PKCS #8: Does not start with PKCS #8 header (SEQUENCE); assume encrypted PKCS #8 not used");
134 		return NULL;
135 	}
136 	pos = hdr.payload;
137 	end = pos + hdr.length;
138 
139 	/* encryptionAlgorithm EncryptionAlgorithmIdentifier */
140 	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
141 	    !asn1_is_sequence(&hdr)) {
142 		asn1_unexpected(&hdr,
143 				"PKCS #8: Expected SEQUENCE (AlgorithmIdentifier); assume encrypted PKCS #8 not used");
144 		return NULL;
145 	}
146 	enc_alg = hdr.payload;
147 	enc_alg_len = hdr.length;
148 	pos = hdr.payload + hdr.length;
149 
150 	/* encryptedData EncryptedData */
151 	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
152 	    !asn1_is_octetstring(&hdr)) {
153 		asn1_unexpected(&hdr,
154 				"PKCS #8: Expected OCTETSTRING (encryptedData)");
155 		return NULL;
156 	}
157 
158 	data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length,
159 			     passwd, &data_len);
160 	if (data) {
161 		struct crypto_private_key *key;
162 		key = pkcs8_key_import(data, data_len);
163 		os_free(data);
164 		return key;
165 	}
166 
167 	return NULL;
168 }
169