Merge branch 'vendor/OPENSSH'
[dragonfly.git] / contrib / hostapd / src / tls / pkcs8.c
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 ||
31             hdr.class != ASN1_CLASS_UNIVERSAL ||
32             hdr.tag != ASN1_TAG_SEQUENCE) {
33                 wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
34                            "header (SEQUENCE); assume PKCS #8 not used");
35                 return NULL;
36         }
37         pos = hdr.payload;
38         end = pos + hdr.length;
39
40         /* version Version (Version ::= INTEGER) */
41         if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
42             hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
43                 wpa_printf(MSG_DEBUG, "PKCS #8: Expected INTEGER - found "
44                            "class %d tag 0x%x; assume PKCS #8 not used",
45                            hdr.class, hdr.tag);
46                 return NULL;
47         }
48
49         zero = bignum_init();
50         if (zero == NULL)
51                 return NULL;
52
53         if (bignum_set_unsigned_bin(zero, hdr.payload, hdr.length) < 0) {
54                 wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse INTEGER");
55                 bignum_deinit(zero);
56                 return NULL;
57         }
58         pos = hdr.payload + hdr.length;
59
60         if (bignum_cmp_d(zero, 0) != 0) {
61                 wpa_printf(MSG_DEBUG, "PKCS #8: Expected zero INTEGER in the "
62                            "beginning of private key; not found; assume "
63                            "PKCS #8 not used");
64                 bignum_deinit(zero);
65                 return NULL;
66         }
67         bignum_deinit(zero);
68
69         /* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier
70          * (PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier) */
71         if (asn1_get_next(pos, len, &hdr) < 0 ||
72             hdr.class != ASN1_CLASS_UNIVERSAL ||
73             hdr.tag != ASN1_TAG_SEQUENCE) {
74                 wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
75                            "(AlgorithmIdentifier) - found class %d tag 0x%x; "
76                            "assume PKCS #8 not used",
77                            hdr.class, hdr.tag);
78                 return NULL;
79         }
80
81         if (asn1_get_oid(hdr.payload, hdr.length, &oid, &pos)) {
82                 wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse OID "
83                            "(algorithm); assume PKCS #8 not used");
84                 return NULL;
85         }
86
87         asn1_oid_to_str(&oid, obuf, sizeof(obuf));
88         wpa_printf(MSG_DEBUG, "PKCS #8: algorithm=%s", obuf);
89
90         if (oid.len != 7 ||
91             oid.oid[0] != 1 /* iso */ ||
92             oid.oid[1] != 2 /* member-body */ ||
93             oid.oid[2] != 840 /* us */ ||
94             oid.oid[3] != 113549 /* rsadsi */ ||
95             oid.oid[4] != 1 /* pkcs */ ||
96             oid.oid[5] != 1 /* pkcs-1 */ ||
97             oid.oid[6] != 1 /* rsaEncryption */) {
98                 wpa_printf(MSG_DEBUG, "PKCS #8: Unsupported private key "
99                            "algorithm %s", obuf);
100                 return NULL;
101         }
102
103         pos = hdr.payload + hdr.length;
104
105         /* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */
106         if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
107             hdr.class != ASN1_CLASS_UNIVERSAL ||
108             hdr.tag != ASN1_TAG_OCTETSTRING) {
109                 wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
110                            "(privateKey) - found class %d tag 0x%x",
111                            hdr.class, hdr.tag);
112                 return NULL;
113         }
114         wpa_printf(MSG_DEBUG, "PKCS #8: Try to parse RSAPrivateKey");
115
116         return (struct crypto_private_key *)
117                 crypto_rsa_import_private_key(hdr.payload, hdr.length);
118 }
119
120
121 struct crypto_private_key *
122 pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd)
123 {
124         struct asn1_hdr hdr;
125         const u8 *pos, *end, *enc_alg;
126         size_t enc_alg_len;
127         u8 *data;
128         size_t data_len;
129
130         if (passwd == NULL)
131                 return NULL;
132
133         /*
134          * PKCS #8, Chapter 7
135          * EncryptedPrivateKeyInfo ::= SEQUENCE {
136          *   encryptionAlgorithm EncryptionAlgorithmIdentifier,
137          *   encryptedData EncryptedData }
138          * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
139          * EncryptedData ::= OCTET STRING
140          */
141
142         if (asn1_get_next(buf, len, &hdr) < 0 ||
143             hdr.class != ASN1_CLASS_UNIVERSAL ||
144             hdr.tag != ASN1_TAG_SEQUENCE) {
145                 wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
146                            "header (SEQUENCE); assume encrypted PKCS #8 not "
147                            "used");
148                 return NULL;
149         }
150         pos = hdr.payload;
151         end = pos + hdr.length;
152
153         /* encryptionAlgorithm EncryptionAlgorithmIdentifier */
154         if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
155             hdr.class != ASN1_CLASS_UNIVERSAL ||
156             hdr.tag != ASN1_TAG_SEQUENCE) {
157                 wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
158                            "(AlgorithmIdentifier) - found class %d tag 0x%x; "
159                            "assume encrypted PKCS #8 not used",
160                            hdr.class, hdr.tag);
161                 return NULL;
162         }
163         enc_alg = hdr.payload;
164         enc_alg_len = hdr.length;
165         pos = hdr.payload + hdr.length;
166
167         /* encryptedData EncryptedData */
168         if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
169             hdr.class != ASN1_CLASS_UNIVERSAL ||
170             hdr.tag != ASN1_TAG_OCTETSTRING) {
171                 wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
172                            "(encryptedData) - found class %d tag 0x%x",
173                            hdr.class, hdr.tag);
174                 return NULL;
175         }
176
177         data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length,
178                              passwd, &data_len);
179         if (data) {
180                 struct crypto_private_key *key;
181                 key = pkcs8_key_import(data, data_len);
182                 os_free(data);
183                 return key;
184         }
185
186         return NULL;
187 }