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