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