]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libstrongswan/plugins/pkcs8/pkcs8_builder.c
cirrus: Explicitly install tpm2-tss-sys package on Alpine
[thirdparty/strongswan.git] / src / libstrongswan / plugins / pkcs8 / pkcs8_builder.c
1 /*
2 * Copyright (C) 2012 Tobias Brunner
3 *
4 * Copyright (C) secunet Security Networks AG
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "pkcs8_builder.h"
18
19 #include <utils/debug.h>
20 #include <asn1/oid.h>
21 #include <asn1/asn1.h>
22 #include <asn1/asn1_parser.h>
23 #include <crypto/pkcs5.h>
24 #include <credentials/keys/private_key.h>
25
26 /**
27 * ASN.1 definition of a privateKeyInfo structure
28 */
29 static const asn1Object_t pkinfoObjects[] = {
30 { 0, "privateKeyInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
31 { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
32 { 1, "privateKeyAlgorithm", ASN1_EOC, ASN1_RAW }, /* 2 */
33 { 1, "privateKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 3 */
34 { 1, "attributes", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 4 */
35 { 1, "end opt", ASN1_EOC, ASN1_END }, /* 5 */
36 { 0, "exit", ASN1_EOC, ASN1_EXIT }
37 };
38 #define PKINFO_PRIVATE_KEY_ALGORITHM 2
39 #define PKINFO_PRIVATE_KEY 3
40
41 /**
42 * Load a generic private key from an ASN.1 encoded blob
43 */
44 static private_key_t *parse_private_key(chunk_t blob)
45 {
46 asn1_parser_t *parser;
47 chunk_t object, params = chunk_empty;
48 int objectID;
49 private_key_t *key = NULL;
50 key_type_t type = KEY_ANY;
51 builder_part_t part = BUILD_BLOB_ASN1_DER;
52
53 parser = asn1_parser_create(pkinfoObjects, blob);
54 parser->set_flags(parser, FALSE, TRUE);
55
56 while (parser->iterate(parser, &objectID, &object))
57 {
58 switch (objectID)
59 {
60 case PKINFO_PRIVATE_KEY_ALGORITHM:
61 {
62 int oid = asn1_parse_algorithmIdentifier(object,
63 parser->get_level(parser) + 1, &params);
64
65 switch (oid)
66 {
67 case OID_RSASSA_PSS:
68 /* TODO: parameters associated with such keys should be
69 * treated as restrictions later when signing (the type
70 * itself is already a restriction). However, the
71 * builders currently don't expect any parameters for
72 * RSA keys (we also only pass along the params, not the
73 * exact type, so we'd have to guess that params
74 * indicate RSA/PSS, but they are optional so that won't
75 * work for keys without specific restrictions) */
76 params = chunk_empty;
77 /* fall-through */
78 case OID_RSA_ENCRYPTION:
79 type = KEY_RSA;
80 break;
81 case OID_EC_PUBLICKEY:
82 type = KEY_ECDSA;
83 break;
84 case OID_ED25519:
85 type = KEY_ED25519;
86 part = BUILD_EDDSA_PRIV_ASN1_DER;
87 break;
88 case OID_ED448:
89 type = KEY_ED448;
90 part = BUILD_EDDSA_PRIV_ASN1_DER;
91 break;
92 default:
93 /* key type not supported */
94 goto end;
95 }
96 break;
97 }
98 case PKINFO_PRIVATE_KEY:
99 {
100 DBG2(DBG_ASN, "-- > --");
101 if (params.len &&
102 !chunk_equals(params, chunk_from_chars(0x05, 0x00)))
103 {
104 key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
105 type, BUILD_BLOB_ALGID_PARAMS,
106 params, part, object, BUILD_END);
107 }
108 else
109 {
110 key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
111 type, part, object, BUILD_END);
112 }
113 DBG2(DBG_ASN, "-- < --");
114 break;
115 }
116 }
117 }
118
119 end:
120 parser->destroy(parser);
121 return key;
122 }
123
124 /**
125 * Try to decrypt the given blob using the given password and pkcs5 object.
126 */
127 static private_key_t *decrypt_private_key_pw(key_type_t type, pkcs5_t *pkcs5,
128 chunk_t blob, chunk_t password)
129 {
130 private_key_t *private_key;
131 chunk_t decrypted;
132
133 if (!pkcs5->decrypt(pkcs5, password, blob, &decrypted))
134 {
135 return NULL;
136 }
137 /* do a quick check to validate whether the password was correct */
138 if (!is_asn1(decrypted))
139 {
140 chunk_clear(&decrypted);
141 return NULL;
142 }
143 private_key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
144 type, BUILD_BLOB_ASN1_DER,
145 decrypted, BUILD_END);
146 chunk_clear(&decrypted);
147 return private_key;
148 }
149
150 /**
151 * Try to decrypt the given blob with multiple passwords using the given
152 * pkcs5 object.
153 */
154 static private_key_t *decrypt_private_key(key_type_t type, pkcs5_t *pkcs5,
155 chunk_t blob)
156 {
157 enumerator_t *enumerator;
158 shared_key_t *shared;
159 private_key_t *private_key;
160
161 private_key = decrypt_private_key_pw(type, pkcs5, blob, chunk_empty);
162 if (private_key)
163 {
164 return private_key;
165 }
166
167 enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
168 SHARED_PRIVATE_KEY_PASS, NULL, NULL);
169 while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
170 {
171 private_key = decrypt_private_key_pw(type, pkcs5, blob,
172 shared->get_key(shared));
173 if (private_key)
174 {
175 break;
176 }
177 }
178 enumerator->destroy(enumerator);
179 return private_key;
180 }
181
182 /**
183 * ASN.1 definition of an encryptedPrivateKeyInfo structure
184 */
185 static const asn1Object_t encryptedPKIObjects[] = {
186 { 0, "encryptedPrivateKeyInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
187 { 1, "encryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 1 */
188 { 1, "encryptedData", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */
189 { 0, "exit", ASN1_EOC, ASN1_EXIT }
190 };
191 #define EPKINFO_ENCRYPTION_ALGORITHM 1
192 #define EPKINFO_ENCRYPTED_DATA 2
193
194 /**
195 * Load an encrypted private key from an ASN.1 encoded blob
196 * Schemes per PKCS#5 (RFC 2898)
197 */
198 static private_key_t *parse_encrypted_private_key(key_type_t type, chunk_t blob)
199 {
200 asn1_parser_t *parser;
201 chunk_t object;
202 int objectID;
203 private_key_t *key = NULL;
204 pkcs5_t *pkcs5 = NULL;
205
206 parser = asn1_parser_create(encryptedPKIObjects, blob);
207
208 while (parser->iterate(parser, &objectID, &object))
209 {
210 switch (objectID)
211 {
212 case EPKINFO_ENCRYPTION_ALGORITHM:
213 {
214 pkcs5 = pkcs5_from_algorithmIdentifier(object,
215 parser->get_level(parser) + 1);
216 if (!pkcs5)
217 {
218 goto end;
219 }
220 break;
221 }
222 case EPKINFO_ENCRYPTED_DATA:
223 {
224 key = decrypt_private_key(type, pkcs5, object);
225 break;
226 }
227 }
228 }
229
230 end:
231 DESTROY_IF(pkcs5);
232 parser->destroy(parser);
233 return key;
234 }
235
236 /**
237 * See header.
238 */
239 private_key_t *pkcs8_private_key_load(key_type_t type, va_list args)
240 {
241 chunk_t blob = chunk_empty;
242 private_key_t *key;
243
244 while (TRUE)
245 {
246 switch (va_arg(args, builder_part_t))
247 {
248 case BUILD_BLOB_ASN1_DER:
249 blob = va_arg(args, chunk_t);
250 continue;
251 case BUILD_END:
252 break;
253 default:
254 return NULL;
255 }
256 break;
257 }
258 /* we don't know whether it is encrypted or not, try both ways */
259 key = parse_encrypted_private_key(type, blob);
260 if (!key)
261 {
262 key = parse_private_key(blob);
263 }
264 return key;
265 }
266