list v3 or v4 fingerprint
[strongswan.git] / src / libstrongswan / plugins / pgp / pgp_cert.c
1 /*
2 * Copyright (C) 2009 Martin Willi
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 "pgp_cert.h"
17 #include "pgp_utils.h"
18
19 #include <time.h>
20
21 #include <debug.h>
22
23 typedef struct private_pgp_cert_t private_pgp_cert_t;
24
25 /**
26 * Private data of an pgp_cert_t object.
27 */
28 struct private_pgp_cert_t {
29
30 /**
31 * Implements pgp_cert_t interface.
32 */
33 pgp_cert_t public;
34
35 /**
36 * Public key of the certificate
37 */
38 public_key_t *key;
39
40 /**
41 * version of the public key
42 */
43 u_int32_t version;
44
45 /**
46 * creation time
47 */
48 u_int32_t created;
49
50 /**
51 * days the certificate is valid
52 */
53 u_int32_t valid;
54
55 /**
56 * userid of the certificate
57 */
58 identification_t *user_id;
59
60 /**
61 * v3 or v4 fingerprint of the PGP public key
62 */
63 chunk_t fingerprint;
64
65 /**
66 * full PGP encoding
67 */
68 chunk_t encoding;
69
70 /**
71 * reference counter
72 */
73 refcount_t ref;
74 };
75
76
77 /**
78 * Implementation of certificate_t.get_type
79 */
80 static certificate_type_t get_type(private_pgp_cert_t *this)
81 {
82 return CERT_GPG;
83 }
84
85 /**
86 * Implementation of certificate_t.get_subject
87 */
88 static identification_t* get_subject(private_pgp_cert_t *this)
89 {
90 return this->user_id;
91 }
92
93 /**
94 * Implementation of certificate_t.get_issuer
95 */
96 static identification_t* get_issuer(private_pgp_cert_t *this)
97 {
98 return this->user_id;
99 }
100
101 /**
102 * Implementation of certificate_t.has_subject.
103 */
104 static id_match_t has_subject(private_pgp_cert_t *this,
105 identification_t *subject)
106 {
107 return this->user_id->matches(this->user_id, subject);
108 }
109
110 /**
111 * Implementation of certificate_t.has_subject.
112 */
113 static id_match_t has_issuer(private_pgp_cert_t *this, identification_t *issuer)
114 {
115 return ID_MATCH_NONE;
116 }
117
118 /**
119 * Implementation of certificate_t.issued_by
120 */
121 static bool issued_by(private_pgp_cert_t *this, certificate_t *issuer)
122 {
123 /* TODO: check signature blobs for a valid signature */
124 return FALSE;
125 }
126
127 /**
128 * Implementation of certificate_t.get_public_key
129 */
130 static public_key_t* get_public_key(private_pgp_cert_t *this)
131 {
132 this->key->get_ref(this->key);
133 return this->key;
134 }
135
136 /**
137 * Implementation of certificate_t.get_ref
138 */
139 static private_pgp_cert_t* get_ref(private_pgp_cert_t *this)
140 {
141 ref_get(&this->ref);
142 return this;
143 }
144
145 /**
146 * Implementation of certificate_t.get_validity.
147 */
148 static bool get_validity(private_pgp_cert_t *this, time_t *when,
149 time_t *not_before, time_t *not_after)
150 {
151 time_t t, until;
152
153 if (when)
154 {
155 t = *when;
156 }
157 else
158 {
159 t = time(NULL);
160 }
161 if (not_before)
162 {
163 *not_before = this->created;
164 }
165 if (this->valid)
166 {
167 until = this->valid + this->created * 24 * 60 * 60;
168 }
169 else
170 {
171 /* Jan 19 03:14:07 UTC 2038 */
172 until = TIME_32_BIT_SIGNED_MAX;
173 }
174 if (not_after)
175 {
176 *not_after = until;
177 }
178 return (t >= this->valid && t <= until);
179 }
180
181 /**
182 * Implementation of certificate_t.is_newer.
183 */
184 static bool is_newer(certificate_t *this, certificate_t *that)
185 {
186 time_t this_update, that_update, now = time(NULL);
187 bool new;
188
189 this->get_validity(this, &now, &this_update, NULL);
190 that->get_validity(that, &now, &that_update, NULL);
191 new = this_update > that_update;
192 DBG1(" certificate from %T is %s - existing certificate from %T %s",
193 &this_update, FALSE, new ? "newer":"not newer",
194 &that_update, FALSE, new ? "replaced":"retained");
195 return new;
196 }
197
198 /**
199 * Implementation of certificate_t.get_encoding.
200 */
201 static chunk_t get_encoding(private_pgp_cert_t *this)
202 {
203 return chunk_clone(this->encoding);
204 }
205
206 /**
207 * Implementation of certificate_t.equals.
208 */
209 static bool equals(private_pgp_cert_t *this, certificate_t *other)
210 {
211 chunk_t encoding;
212 bool equal;
213
214 if (this == (private_pgp_cert_t*)other)
215 {
216 return TRUE;
217 }
218 if (other->get_type(other) != CERT_X509)
219 {
220 return FALSE;
221 }
222 if (other->equals == (void*)equals)
223 { /* skip allocation if we have the same implementation */
224 return chunk_equals(this->encoding, ((private_pgp_cert_t*)other)->encoding);
225 }
226 encoding = other->get_encoding(other);
227 equal = chunk_equals(this->encoding, encoding);
228 free(encoding.ptr);
229 return equal;
230 }
231
232 /**
233 * Implementation of pgp_cert_t.destroy.
234 */
235 static void destroy(private_pgp_cert_t *this)
236 {
237 if (ref_put(&this->ref))
238 {
239 DESTROY_IF(this->key);
240 DESTROY_IF(this->user_id);
241 free(this->fingerprint.ptr);
242 free(this->encoding.ptr);
243 free(this);
244 }
245 }
246
247 /**
248 * Implementation of pgp_certificate_t.get_fingerprint.
249 */
250 static chunk_t get_fingerprint(private_pgp_cert_t *this)
251 {
252 return this->fingerprint;
253 }
254
255 /**
256 * See header
257 */
258 private_pgp_cert_t *create_empty()
259 {
260 private_pgp_cert_t *this = malloc_thing(private_pgp_cert_t);
261
262 this->public.interface.interface.get_type = (certificate_type_t (*) (certificate_t*))get_type;
263 this->public.interface.interface.get_subject = (identification_t* (*) (certificate_t*))get_subject;
264 this->public.interface.interface.get_issuer = (identification_t* (*) (certificate_t*))get_issuer;
265 this->public.interface.interface.has_subject = (id_match_t (*) (certificate_t*, identification_t*))has_subject;
266 this->public.interface.interface.has_issuer = (id_match_t (*) (certificate_t*, identification_t*))has_issuer;
267 this->public.interface.interface.issued_by = (bool (*) (certificate_t*, certificate_t*))issued_by;
268 this->public.interface.interface.get_public_key = (public_key_t* (*) (certificate_t*))get_public_key;
269 this->public.interface.interface.get_validity = (bool (*) (certificate_t*, time_t*, time_t*, time_t*))get_validity;
270 this->public.interface.interface.is_newer = (bool (*) (certificate_t*,certificate_t*))is_newer;
271 this->public.interface.interface.get_encoding = (chunk_t (*) (certificate_t*))get_encoding;
272 this->public.interface.interface.equals = (bool (*)(certificate_t*, certificate_t*))equals;
273 this->public.interface.interface.get_ref = (certificate_t* (*)(certificate_t*))get_ref;
274 this->public.interface.interface.destroy = (void (*)(certificate_t*))destroy;
275 this->public.interface.get_fingerprint = (chunk_t (*)(pgp_certificate_t*))get_fingerprint;
276
277 this->key = NULL;
278 this->version = 0;
279 this->created = 0;
280 this->valid = 0;
281 this->user_id = NULL;
282 this->fingerprint = chunk_empty;
283 this->encoding = chunk_empty;
284 this->ref = 1;
285
286 return this;
287 }
288
289 /**
290 * Parse the public key packet of a PGP certificate
291 */
292 static bool parse_public_key(private_pgp_cert_t *this, chunk_t packet)
293 {
294 chunk_t pubkey_packet = packet;
295
296 if (!pgp_read_scalar(&packet, 1, &this->version))
297 {
298 return FALSE;
299 }
300 switch (this->version)
301 {
302 case 3:
303 if (!pgp_read_scalar(&packet, 4, &this->created) ||
304 !pgp_read_scalar(&packet, 2, &this->valid))
305 {
306 return FALSE;
307 }
308 break;
309 case 4:
310 if (!pgp_read_scalar(&packet, 4, &this->created))
311 {
312 return FALSE;
313 }
314 break;
315 default:
316 DBG1("PGP packet version V%d not supported", this->version);
317 return FALSE;
318 }
319 DESTROY_IF(this->key);
320 this->key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY,
321 BUILD_BLOB_PGP, packet, BUILD_END);
322 if (this->key == NULL)
323 {
324 return FALSE;
325 }
326
327 /* compute V4 or V3 fingerprint according to section 12.2 of RFC 4880 */
328 if (this->version == 4)
329 {
330 chunk_t pubkey_packet_header = chunk_from_chars(
331 0x99, pubkey_packet.len / 256, pubkey_packet.len % 256
332 );
333 hasher_t *hasher;
334
335 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
336 if (hasher == NULL)
337 {
338 DBG1("no SHA-1 hasher available");
339 return FALSE;
340 }
341 hasher->allocate_hash(hasher, pubkey_packet_header, NULL);
342 hasher->allocate_hash(hasher, pubkey_packet, &this->fingerprint);
343 hasher->destroy(hasher);
344 }
345 else
346 {
347 /* V3 fingerprint is computed by public_key_t class */
348 if (!this->key->get_fingerprint(this->key, KEY_ID_PGPV3,
349 &this->fingerprint))
350 {
351 return FALSE;
352 }
353 this->fingerprint = chunk_clone(this->fingerprint);
354 }
355 return TRUE;
356 }
357
358 /**
359 * Parse the signature packet of a PGP certificate
360 */
361 static bool parse_signature(private_pgp_cert_t *this, chunk_t packet)
362 {
363 u_int32_t version, len, type, created;
364
365 if (!pgp_read_scalar(&packet, 1, &version))
366 {
367 return FALSE;
368 }
369 /* we parse only V3 signature packets */
370 if (version != 3)
371 {
372 DBG1(" skipped V%d PGP signature", version);
373 return TRUE;
374 }
375 if (!pgp_read_scalar(&packet, 1, &len) || len != 5)
376 {
377 return FALSE;
378 }
379 if (!pgp_read_scalar(&packet, 1, &type) ||
380 !pgp_read_scalar(&packet, 1, &created))
381 {
382 return FALSE;
383 }
384 /* TODO: parse and save signature to a list */
385 return TRUE;
386 }
387
388 /**
389 * Parse the userid packet of a PGP certificate
390 */
391 static bool parse_user_id(private_pgp_cert_t *this, chunk_t packet)
392 {
393 DESTROY_IF(this->user_id);
394 this->user_id = identification_create_from_encoding(ID_KEY_ID, packet);
395 return TRUE;
396 }
397
398 /**
399 * See header.
400 */
401 pgp_cert_t *pgp_cert_load(certificate_type_t type, va_list args)
402 {
403 chunk_t packet, blob = chunk_empty;
404 pgp_packet_tag_t tag;
405 private_pgp_cert_t *this;
406
407 while (TRUE)
408 {
409 switch (va_arg(args, builder_part_t))
410 {
411 case BUILD_BLOB_PGP:
412 blob = va_arg(args, chunk_t);
413 continue;
414 case BUILD_END:
415 break;
416 default:
417 return NULL;
418 }
419 break;
420 }
421
422 this = create_empty();
423 this->encoding = chunk_clone(blob);
424 while (blob.len)
425 {
426 if (!pgp_read_packet(&blob, &packet, &tag))
427 {
428 destroy(this);
429 return NULL;
430 }
431 switch (tag)
432 {
433 case PGP_PKT_PUBLIC_KEY:
434 if (!parse_public_key(this, packet))
435 {
436 destroy(this);
437 return NULL;
438 }
439 break;
440 case PGP_PKT_SIGNATURE:
441 if (!parse_signature(this, packet))
442 {
443 destroy(this);
444 return FALSE;
445 }
446 break;
447 case PGP_PKT_USER_ID:
448 if (!parse_user_id(this, packet))
449 {
450 destroy(this);
451 return FALSE;
452 }
453 break;
454 default:
455 DBG1("ignoring %N packet in PGP certificate",
456 pgp_packet_tag_names, tag);
457 break;
458 }
459 }
460 if (this->key)
461 {
462 return &this->public;
463 }
464 destroy(this);
465 return NULL;
466 }
467