Updated pgp plugin to the new builder API
[strongswan.git] / src / libstrongswan / plugins / pgp / pgp_builder.c
1 /*
2 * Copyright (C) 2009 Martin Willi
3 * Copyright (C) 2002-2009 Andreas Steffen
4 * Hochschule fuer Technik Rapperswil
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 "pgp_builder.h"
18
19 #include <enum.h>
20 #include <debug.h>
21 #include <credentials/keys/private_key.h>
22
23 typedef enum pgp_pubkey_alg_t pgp_pubkey_alg_t;
24 typedef enum pgp_sym_alg_t pgp_sym_alg_t;
25
26 /**
27 * OpenPGP public key algorithms as defined in section 9.1 of RFC 4880
28 */
29 enum pgp_pubkey_alg_t {
30 PGP_PUBKEY_ALG_RSA = 1,
31 PGP_PUBKEY_ALG_RSA_ENC_ONLY = 2,
32 PGP_PUBKEY_ALG_RSA_SIGN_ONLY = 3,
33 PGP_PUBKEY_ALG_ELGAMAL_ENC_ONLY = 16,
34 PGP_PUBKEY_ALG_DSA = 17,
35 PGP_PUBKEY_ALG_ECC = 18,
36 PGP_PUBKEY_ALG_ECDSA = 19,
37 PGP_PUBKEY_ALG_ELGAMAL = 20,
38 PGP_PUBKEY_ALG_DIFFIE_HELLMAN = 21,
39 };
40
41 /**
42 * OpenPGP symmetric key algorithms as defined in section 9.2 of RFC 4880
43 */
44 enum pgp_sym_alg_t {
45 PGP_SYM_ALG_PLAIN = 0,
46 PGP_SYM_ALG_IDEA = 1,
47 PGP_SYM_ALG_3DES = 2,
48 PGP_SYM_ALG_CAST5 = 3,
49 PGP_SYM_ALG_BLOWFISH = 4,
50 PGP_SYM_ALG_SAFER = 5,
51 PGP_SYM_ALG_DES = 6,
52 PGP_SYM_ALG_AES_128 = 7,
53 PGP_SYM_ALG_AES_192 = 8,
54 PGP_SYM_ALG_AES_256 = 9,
55 PGP_SYM_ALG_TWOFISH = 10
56 };
57
58 ENUM_BEGIN(pgp_pubkey_alg_names, PGP_PUBKEY_ALG_RSA, PGP_PUBKEY_ALG_RSA_SIGN_ONLY,
59 "RSA",
60 "RSA_ENC_ONLY",
61 "RSA_SIGN_ONLY"
62 );
63 ENUM_NEXT(pgp_pubkey_alg_names, PGP_PUBKEY_ALG_ELGAMAL_ENC_ONLY, PGP_PUBKEY_ALG_DIFFIE_HELLMAN, PGP_PUBKEY_ALG_RSA_SIGN_ONLY,
64 "ELGAMAL_ENC_ONLY",
65 "DSA",
66 "ECC",
67 "ECDSA",
68 "ELGAMAL",
69 "DIFFIE_HELLMAN"
70 );
71 ENUM_END(pgp_pubkey_alg_names, PGP_PUBKEY_ALG_DIFFIE_HELLMAN);
72
73 ENUM(pgp_sym_alg_names, PGP_SYM_ALG_PLAIN, PGP_SYM_ALG_TWOFISH,
74 "PLAINTEXT",
75 "IDEA",
76 "3DES",
77 "CAST5",
78 "BLOWFISH",
79 "SAFER",
80 "DES",
81 "AES_128",
82 "AES_192",
83 "AES_256",
84 "TWOFISH"
85 );
86
87 /**
88 * Read a PGP scalar of bytes length, advance blob
89 */
90 static bool read_scalar(chunk_t *blob, size_t bytes, u_int32_t *scalar)
91 {
92 u_int32_t res = 0;
93
94 if (bytes > blob->len)
95 {
96 DBG1("PGP data too short to read %d byte scalar", bytes);
97 return FALSE;
98 }
99 while (bytes-- > 0)
100 {
101 res = 256 * res + blob->ptr[0];
102 *blob = chunk_skip(*blob, 1);
103 }
104 *scalar = res;
105 return TRUE;
106 }
107
108 /**
109 * Read length of an PGP old packet length encoding
110 */
111 static bool old_packet_length(chunk_t *blob, u_int32_t *length)
112 {
113 /* bits 0 and 1 define the packet length type */
114 u_char type;
115
116 if (!blob->len)
117 {
118 return FALSE;
119 }
120 type = 0x03 & blob->ptr[0];
121 *blob = chunk_skip(*blob, 1);
122
123 if (type > 2)
124 {
125 return FALSE;
126 }
127 return read_scalar(blob, type == 0 ? 1 : type * 2, length);
128 }
129
130 /**
131 * Read a PGP MPI, advance blob
132 */
133 static bool read_mpi(chunk_t *blob, chunk_t *mpi)
134 {
135 u_int32_t bits, bytes;
136
137 if (!read_scalar(blob, 2, &bits))
138 {
139 DBG1("PGP data too short to read MPI length");
140 return FALSE;
141 }
142 bytes = (bits + 7) / 8;
143 if (bytes > blob->len)
144 {
145 DBG1("PGP data too short to read %d byte MPI", bytes);
146 return FALSE;
147 }
148 *mpi = chunk_create(blob->ptr, bytes);
149 *blob = chunk_skip(*blob, bytes);
150 return TRUE;
151 }
152
153 /**
154 * Load a generic public key from a PGP packet
155 */
156 static public_key_t *parse_public_key(chunk_t blob)
157 {
158 u_int32_t alg;
159 public_key_t *key;
160
161 if (!read_scalar(&blob, 1, &alg))
162 {
163 return NULL;
164 }
165 switch (alg)
166 {
167 case PGP_PUBKEY_ALG_RSA:
168 case PGP_PUBKEY_ALG_RSA_SIGN_ONLY:
169 key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
170 BUILD_BLOB_PGP, blob, BUILD_END);
171 break;
172 default:
173 DBG1("PGP public key algorithm %N not supported",
174 pgp_pubkey_alg_names, alg);
175 return NULL;
176 }
177 return key;
178 }
179
180 /**
181 * Load a RSA public key from a PGP packet
182 */
183 static public_key_t *parse_rsa_public_key(chunk_t blob)
184 {
185 chunk_t mpi[2];
186 int i;
187
188 for (i = 0; i < 2; i++)
189 {
190 if (!read_mpi(&blob, &mpi[i]))
191 {
192 return NULL;
193 }
194 }
195 return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
196 BUILD_RSA_MODULUS, mpi[0], BUILD_RSA_PUB_EXP, mpi[1],
197 BUILD_END);
198 }
199
200 /**
201 * Load a RSA private key from a PGP packet
202 */
203 static private_key_t *parse_rsa_private_key(chunk_t blob)
204 {
205 chunk_t mpi[6];
206 u_int32_t s2k;
207 int i;
208
209 for (i = 0; i < 2; i++)
210 {
211 if (!read_mpi(&blob, &mpi[i]))
212 {
213 return NULL;
214 }
215 }
216 if (!read_scalar(&blob, 1, &s2k))
217 {
218 return NULL;
219 }
220 if (s2k == 255 || s2k == 254)
221 {
222 DBG1("string-to-key specifiers not supported");
223 return NULL;
224 }
225 if (s2k != PGP_SYM_ALG_PLAIN)
226 {
227 DBG1("%N private key encryption not supported", pgp_sym_alg_names, s2k);
228 return NULL;
229 }
230
231 for (i = 2; i < 6; i++)
232 {
233 if (!read_mpi(&blob, &mpi[i]))
234 {
235 return NULL;
236 }
237 }
238
239 /* PGP has uses p < q, but we use p > q */
240 return lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
241 BUILD_RSA_MODULUS, mpi[0], BUILD_RSA_PUB_EXP, mpi[1],
242 BUILD_RSA_PRIV_EXP, mpi[2], BUILD_RSA_PRIME2, mpi[3],
243 BUILD_RSA_PRIME1, mpi[4], BUILD_RSA_COEFF, mpi[5],
244 BUILD_END);
245 }
246
247 /**
248 * Implementation of private_key_t.sign for encryption-only keys
249 */
250 static bool sign_not_allowed(private_key_t *this, signature_scheme_t scheme,
251 chunk_t data, chunk_t *signature)
252 {
253 DBG1("signing failed - decryption only key");
254 return FALSE;
255 }
256
257 /**
258 * Implementation of private_key_t.decrypt for signature-only keys
259 */
260 static bool decrypt_not_allowed(private_key_t *this,
261 chunk_t crypto, chunk_t *plain)
262 {
263 DBG1("decryption failed - signature only key");
264 return FALSE;
265 }
266
267 /**
268 * Load a generic private key from a PGP packet
269 */
270 static private_key_t *parse_private_key(chunk_t blob)
271 {
272 chunk_t packet;
273 u_char tag, type;
274 u_int32_t len, version, created, days, alg;
275 private_key_t *key;
276
277 tag = blob.ptr[0];
278
279 /* bit 7 must be set */
280 if (!(tag & 0x80))
281 {
282 DBG1("invalid packet tag");
283 return NULL;
284 }
285 /* bit 6 set defines new packet format */
286 if (tag & 0x40)
287 {
288 DBG1("new PGP packet format not supported");
289 return NULL;
290 }
291
292 type = (tag & 0x3C) >> 2;
293 if (!old_packet_length(&blob, &len) || len > blob.len)
294 {
295 DBG1("invalid packet length");
296 return NULL;
297 }
298 packet.len = len;
299 packet.ptr = blob.ptr;
300 blob = chunk_skip(blob, len);
301
302 if (!read_scalar(&packet, 1, &version))
303 {
304 return NULL;
305 }
306 if (version < 3 || version > 4)
307 {
308 DBG1("OpenPGP packet version V%d not supported", version);
309 return NULL;
310 }
311 if (!read_scalar(&packet, 4, &created))
312 {
313 return NULL;
314 }
315 if (version == 3)
316 {
317 if (!read_scalar(&packet, 2, &days))
318 {
319 return NULL;
320 }
321 }
322 if (!read_scalar(&packet, 1, &alg))
323 {
324 return NULL;
325 }
326 switch (alg)
327 {
328 case PGP_PUBKEY_ALG_RSA:
329 return lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
330 BUILD_BLOB_PGP, packet, BUILD_END);
331 case PGP_PUBKEY_ALG_RSA_ENC_ONLY:
332 key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
333 BUILD_BLOB_PGP, packet, BUILD_END);
334 if (key)
335 {
336 key->sign = sign_not_allowed;
337 }
338 return key;
339 case PGP_PUBKEY_ALG_RSA_SIGN_ONLY:
340 key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
341 BUILD_BLOB_PGP, packet, BUILD_END);
342 if (key)
343 {
344 key->decrypt = decrypt_not_allowed;
345 }
346 return key;
347 case PGP_PUBKEY_ALG_ECDSA:
348 return lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ECDSA,
349 BUILD_BLOB_PGP, packet, BUILD_END);
350 case PGP_PUBKEY_ALG_ELGAMAL_ENC_ONLY:
351 case PGP_PUBKEY_ALG_DSA:
352 case PGP_PUBKEY_ALG_ECC:
353 case PGP_PUBKEY_ALG_ELGAMAL:
354 case PGP_PUBKEY_ALG_DIFFIE_HELLMAN:
355 default:
356 return NULL;
357 }
358 }
359
360 /**
361 * See header.
362 */
363 public_key_t *pgp_public_key_load(key_type_t type, va_list args)
364 {
365 chunk_t blob = chunk_empty;
366
367 while (TRUE)
368 {
369 switch (va_arg(args, builder_part_t))
370 {
371 case BUILD_BLOB_PGP:
372 blob = va_arg(args, chunk_t);
373 continue;
374 case BUILD_END:
375 break;
376 default:
377 return NULL;
378 }
379 break;
380 }
381 switch (type)
382 {
383 case KEY_ANY:
384 return parse_public_key(blob);
385 case KEY_RSA:
386 return parse_rsa_public_key(blob);
387 default:
388 return NULL;
389 }
390 }
391
392 /**
393 * See header.
394 */
395 private_key_t *pgp_private_key_load(key_type_t type, va_list args)
396 {
397 chunk_t blob = chunk_empty;
398
399 while (TRUE)
400 {
401 switch (va_arg(args, builder_part_t))
402 {
403 case BUILD_BLOB_PGP:
404 blob = va_arg(args, chunk_t);
405 continue;
406 case BUILD_END:
407 break;
408 default:
409 return NULL;
410 }
411 break;
412 }
413 switch (type)
414 {
415 case KEY_ANY:
416 return parse_private_key(blob);
417 case KEY_RSA:
418 return parse_rsa_private_key(blob);
419 default:
420 return NULL;
421 }
422 }
423