moved PGP types to pgp/pgp.h
[strongswan.git] / src / pluto / pgpcert.c
1 /* Support of OpenPGP certificates
2 * Copyright (C) 2002-2009 Andreas Steffen
3 *
4 * HSR - 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 <stdlib.h>
18 #include <string.h>
19 #include <time.h>
20
21 #include <freeswan.h>
22
23 #include <library.h>
24 #include <pgp/pgp.h>
25 #include <crypto/hashers/hasher.h>
26
27 #include "constants.h"
28 #include "defs.h"
29 #include "mp_defs.h"
30 #include "log.h"
31 #include "id.h"
32 #include "pgpcert.h"
33 #include "certs.h"
34 #include "whack.h"
35 #include "keys.h"
36
37 /*
38 * chained list of OpenPGP end certificates
39 */
40 static pgpcert_t *pgpcerts = NULL;
41
42 /*
43 * Size of PGP Key ID
44 */
45 #define PGP_KEYID_SIZE 8
46
47 const pgpcert_t empty_pgpcert = {
48 NULL , /* *next */
49 0 , /* installed */
50 0 , /* count */
51 { NULL, 0 }, /* certificate */
52 0 , /* created */
53 0 , /* until */
54 NULL , /* public key */
55 NULL /* fingerprint */
56 };
57
58
59 /*
60 * extracts the length of a PGP packet
61 */
62 static size_t pgp_old_packet_length(chunk_t *blob)
63 {
64 /* bits 0 and 1 define the packet length type */
65 int len_type = 0x03 & *blob->ptr++;
66
67 blob->len--;
68
69 /* len_type: 0 -> 1 byte, 1 -> 2 bytes, 2 -> 4 bytes */
70 return pgp_length(blob, (len_type == 0)? 1: len_type << 1);
71 }
72
73 /*
74 * extracts PGP packet version (V3 or V4)
75 */
76 static u_char pgp_version(chunk_t *blob)
77 {
78 u_char version = *blob->ptr++;
79 blob->len--;
80 DBG(DBG_PARSING,
81 DBG_log("L3 - version:");
82 DBG_log(" V%d", version)
83 )
84 return version;
85 }
86
87 /*
88 * Parse OpenPGP public key packet defined in section 5.5.2 of RFC 2440
89 */
90 static bool parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
91 {
92 u_char version = pgp_version(packet);
93 public_key_t *key;
94
95 if (version < 3 || version > 4)
96 {
97 plog("PGP packet version V%d not supported", version);
98 return FALSE;
99 }
100
101 /* creation date - 4 bytes */
102 cert->created = (time_t)pgp_length(packet, 4);
103 DBG(DBG_PARSING,
104 DBG_log("L3 - created:");
105 DBG_log(" %T", &cert->created, TRUE)
106 )
107
108 if (version == 3)
109 {
110 /* validity in days - 2 bytes */
111 cert->until = (time_t)pgp_length(packet, 2);
112
113 /* validity of 0 days means that the key never expires */
114 if (cert->until > 0)
115 {
116 cert->until = cert->created + 24*3600*cert->until;
117 }
118 DBG(DBG_PARSING,
119 DBG_log("L3 - until:");
120 DBG_log(" %T", &cert->until, TRUE);
121 )
122 }
123
124 /* public key algorithm - 1 byte */
125 DBG(DBG_PARSING,
126 DBG_log("L3 - public key algorithm:")
127 )
128
129 switch (pgp_length(packet, 1))
130 {
131 case PGP_PUBKEY_ALG_RSA:
132 case PGP_PUBKEY_ALG_RSA_SIGN_ONLY:
133 DBG(DBG_PARSING,
134 DBG_log(" RSA")
135 )
136 key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
137 BUILD_BLOB_PGP, *packet,
138 BUILD_END);
139 if (key == NULL)
140 {
141 return FALSE;
142 }
143 cert->public_key = key;
144
145 if (version == 3)
146 {
147 cert->fingerprint = key->get_id(key, ID_KEY_ID);
148 if (cert->fingerprint == NULL)
149 {
150 return FALSE;
151 }
152 }
153 else
154 {
155 plog(" computation of V4 key ID not implemented yet");
156 }
157 break;
158 case PGP_PUBKEY_ALG_DSA:
159 DBG(DBG_PARSING,
160 DBG_log(" DSA")
161 )
162 plog(" DSA public keys not supported");
163 return FALSE;
164 default:
165 DBG(DBG_PARSING,
166 DBG_log(" other")
167 )
168 plog(" exotic not RSA public keys not supported");
169 return FALSE;
170 }
171 return TRUE;
172 }
173
174 /*
175 * Parse OpenPGP signature packet defined in section 5.2.2 of RFC 2440
176 */
177 static bool parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert)
178 {
179 time_t created;
180 chunk_t keyid;
181 u_char sig_type;
182 u_char version = pgp_version(packet);
183
184 /* we parse only V3 signature packets */
185 if (version != 3)
186 return TRUE;
187
188 /* size byte must have the value 5 */
189 if (pgp_length(packet, 1) != 5)
190 {
191 plog(" size must be 5");
192 return FALSE;
193 }
194
195 /* signature type - 1 byte */
196 sig_type = (u_char)pgp_length(packet, 1);
197 DBG(DBG_PARSING,
198 DBG_log("L3 - signature type: 0x%2x", sig_type)
199 )
200
201 /* creation date - 4 bytes */
202 created = (time_t)pgp_length(packet, 4);
203 DBG(DBG_PARSING,
204 DBG_log("L3 - created:");
205 DBG_log(" %T", &cert->created, TRUE)
206 )
207
208 /* key ID of signer - 8 bytes */
209 keyid.ptr = packet->ptr;
210 keyid.len = PGP_KEYID_SIZE;
211 DBG_cond_dump_chunk(DBG_PARSING, "L3 - key ID of signer", keyid);
212
213 return TRUE;
214 }
215
216 bool parse_pgp(chunk_t blob, pgpcert_t *cert, private_key_t **key)
217 {
218 DBG(DBG_PARSING,
219 DBG_log("L0 - PGP file:")
220 )
221 DBG_cond_dump_chunk(DBG_RAW, "", blob);
222
223 if (cert != NULL)
224 {
225 /* parse a PGP certificate file */
226 cert->certificate = blob;
227 time(&cert->installed);
228 }
229 else if (key == NULL)
230 {
231 /* should not occur, nothing to parse */
232 return FALSE;
233 }
234
235 while (blob.len > 0)
236 {
237 chunk_t packet = chunk_empty;
238 u_char packet_tag = *blob.ptr;
239
240 DBG(DBG_PARSING,
241 DBG_log("L1 - PGP packet: tag= 0x%2x", packet_tag)
242 )
243
244 /* bit 7 must be set */
245 if (!(packet_tag & 0x80))
246 {
247 plog(" incorrect Packet Tag");
248 return FALSE;
249 }
250
251 /* bit 6 set defines new packet format */
252 if (packet_tag & 0x40)
253 {
254 plog(" new PGP packet format not supported");
255 return FALSE;
256 }
257 else
258 {
259 int packet_type = (packet_tag & 0x3C) >> 2;
260
261 packet.len = pgp_old_packet_length(&blob);
262 packet.ptr = blob.ptr;
263 blob.ptr += packet.len;
264 blob.len -= packet.len;
265 DBG(DBG_PARSING,
266 DBG_log(" %N (%d), old format, %u bytes",
267 pgp_packet_tag_names, packet_type,
268 packet_type, packet.len);
269 DBG_log("L2 - body:")
270 )
271 DBG_cond_dump_chunk(DBG_RAW, "", packet);
272
273 if (cert != NULL)
274 {
275 /* parse a PGP certificate */
276 switch (packet_type)
277 {
278 case PGP_PKT_PUBLIC_KEY:
279 if (!parse_pgp_pubkey_packet(&packet, cert))
280 {
281 return FALSE;
282 }
283 break;
284 case PGP_PKT_SIGNATURE:
285 if (!parse_pgp_signature_packet(&packet, cert))
286 {
287 return FALSE;
288 }
289 break;
290 case PGP_PKT_USER_ID:
291 DBG(DBG_PARSING,
292 DBG_log("L3 - user ID:");
293 DBG_log(" '%.*s'", (int)packet.len, packet.ptr)
294 )
295 break;
296 default:
297 break;
298 }
299 }
300 else
301 {
302 /* parse a PGP private key file */
303 switch (packet_type)
304 {
305 case PGP_PKT_SECRET_KEY:
306 *key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
307 BUILD_BLOB_PGP, packet,
308 BUILD_END);
309 break;
310 default:
311 break;
312 }
313 if (*key == NULL)
314 {
315 return FALSE;
316 }
317
318 }
319 }
320 }
321 return TRUE;
322 }
323
324 /*
325 * compare two OpenPGP certificates
326 */
327 static bool same_pgpcert(pgpcert_t *a, pgpcert_t *b)
328 {
329 return a->certificate.len == b->certificate.len &&
330 memeq(a->certificate.ptr, b->certificate.ptr, b->certificate.len);
331 }
332
333 /*
334 * for each link pointing to the certificate increase the count by one
335 */
336 void share_pgpcert(pgpcert_t *cert)
337 {
338 if (cert != NULL)
339 {
340 cert->count++;
341 }
342 }
343
344 /*
345 * select the OpenPGP keyid as ID
346 */
347 void select_pgpcert_id(pgpcert_t *cert, struct id *end_id)
348 {
349 end_id->kind = ID_KEY_ID;
350 end_id->name = cert->fingerprint->get_encoding(cert->fingerprint);
351 end_id->name = chunk_clone(end_id->name);
352 }
353
354 /*
355 * add an OpenPGP user/host certificate to the chained list
356 */
357 pgpcert_t* add_pgpcert(pgpcert_t *cert)
358 {
359 pgpcert_t *c = pgpcerts;
360
361 while (c != NULL)
362 {
363 if (same_pgpcert(c, cert)) /* already in chain, free cert */
364 {
365 free_pgpcert(cert);
366 return c;
367 }
368 c = c->next;
369 }
370
371 /* insert new cert at the root of the chain */
372 cert->next = pgpcerts;
373 pgpcerts = cert;
374 DBG(DBG_CONTROL | DBG_PARSING,
375 DBG_log(" pgp cert inserted")
376 )
377 return cert;
378 }
379
380 /* release of a certificate decreases the count by one
381 " the certificate is freed when the counter reaches zero
382 */
383 void release_pgpcert(pgpcert_t *cert)
384 {
385 if (cert != NULL && --cert->count == 0)
386 {
387 pgpcert_t **pp = &pgpcerts;
388 while (*pp != cert)
389 {
390 pp = &(*pp)->next;
391 }
392 *pp = cert->next;
393 free_pgpcert(cert);
394 }
395 }
396
397 /*
398 * free a PGP certificate
399 */
400 void free_pgpcert(pgpcert_t *cert)
401 {
402 if (cert != NULL)
403 {
404 DESTROY_IF(cert->public_key);
405 DESTROY_IF(cert->fingerprint);
406 free(cert->certificate.ptr);
407 free(cert);
408 }
409 }
410
411 /*
412 * list all PGP end certificates in a chained list
413 */
414 void list_pgp_end_certs(bool utc)
415 {
416 pgpcert_t *cert = pgpcerts;
417 time_t now;
418
419 /* determine the current time */
420 time(&now);
421
422 if (cert != NULL)
423 {
424 whack_log(RC_COMMENT, " ");
425 whack_log(RC_COMMENT, "List of PGP End certificates:");
426 whack_log(RC_COMMENT, " ");
427 }
428
429 while (cert != NULL)
430 {
431 public_key_t *key = cert->public_key;
432 cert_t c;
433
434 c.type = CERT_PGP;
435 c.u.pgp = cert;
436
437 whack_log(RC_COMMENT, "%T, count: %d", &cert->installed, utc, cert->count);
438 whack_log(RC_COMMENT, " fingerprint: %Y", cert->fingerprint);
439 whack_log(RC_COMMENT, " pubkey: %N %4d bits%s",
440 key_type_names, key->get_type(key),
441 key->get_keysize(key) * BITS_PER_BYTE,
442 has_private_key(c)? ", has private key" : "");
443 whack_log(RC_COMMENT, " keyid: %Y",
444 key->get_id(key, ID_PUBKEY_INFO_SHA1));
445 whack_log(RC_COMMENT, " created: %T", &cert->created, utc);
446 whack_log(RC_COMMENT, " until: %T %s", &cert->until, utc,
447 check_expiry(cert->until, CA_CERT_WARNING_INTERVAL, TRUE));
448 cert = cert->next;
449 }
450 }
451