2 * Copyright (C) 2009 Martin Willi
4 * Copyright (C) secunet Security Networks AG
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>.
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
18 #include "pgp_utils.h"
22 #include <utils/debug.h>
24 typedef struct private_pgp_cert_t private_pgp_cert_t
;
27 * Private data of an pgp_cert_t object.
29 struct private_pgp_cert_t
{
32 * Implements pgp_cert_t interface.
37 * Public key of the certificate
42 * version of the public key
52 * days the certificate is valid
57 * userid of the certificate
59 identification_t
*user_id
;
62 * v3 or v4 fingerprint of the PGP public key
78 METHOD(certificate_t
, get_type
, certificate_type_t
,
79 private_pgp_cert_t
*this)
84 METHOD(certificate_t
, get_subject
,identification_t
*,
85 private_pgp_cert_t
*this)
90 METHOD(certificate_t
, get_issuer
, identification_t
*,
91 private_pgp_cert_t
*this)
96 METHOD(certificate_t
, has_subject
, id_match_t
,
97 private_pgp_cert_t
*this, identification_t
*subject
)
99 id_match_t match_user_id
;
101 match_user_id
= this->user_id
->matches(this->user_id
, subject
);
102 if (match_user_id
== ID_MATCH_NONE
&&
103 subject
->get_type(subject
) == ID_KEY_ID
&&
104 chunk_equals(this->fingerprint
, subject
->get_encoding(subject
)))
106 return ID_MATCH_PERFECT
;
108 return match_user_id
;
111 METHOD(certificate_t
, has_issuer
, id_match_t
,
112 private_pgp_cert_t
*this, identification_t
*issuer
)
114 return ID_MATCH_NONE
;
117 METHOD(certificate_t
, issued_by
,bool,
118 private_pgp_cert_t
*this, certificate_t
*issuer
, signature_params_t
**scheme
)
120 /* TODO: check signature blobs for a valid signature */
124 METHOD(certificate_t
, get_public_key
, public_key_t
*,
125 private_pgp_cert_t
*this)
127 this->key
->get_ref(this->key
);
131 METHOD(certificate_t
, get_ref
, certificate_t
*,
132 private_pgp_cert_t
*this)
135 return &this->public.interface
.interface
;
138 METHOD(certificate_t
, get_validity
, bool,
139 private_pgp_cert_t
*this, time_t *when
, time_t *not_before
,
154 *not_before
= this->created
;
158 until
= this->valid
+ this->created
* 24 * 60 * 60;
162 /* Jan 19 03:14:07 UTC 2038 */
163 until
= TIME_32_BIT_SIGNED_MAX
;
169 return (t
>= this->valid
&& t
<= until
);
172 METHOD(certificate_t
, get_encoding
, bool,
173 private_pgp_cert_t
*this, cred_encoding_type_t type
, chunk_t
*encoding
)
175 if (type
== CERT_PGP_PKT
)
177 *encoding
= chunk_clone(this->encoding
);
180 return lib
->encoding
->encode(lib
->encoding
, type
, NULL
, encoding
,
181 CRED_PART_PGP_CERT
, this->encoding
, CRED_PART_END
);
184 METHOD(certificate_t
, equals
, bool,
185 private_pgp_cert_t
*this, certificate_t
*other
)
190 if (this == (private_pgp_cert_t
*)other
)
194 if (other
->get_type(other
) != CERT_X509
)
198 if (other
->equals
== (void*)equals
)
199 { /* skip allocation if we have the same implementation */
200 return chunk_equals(this->encoding
, ((private_pgp_cert_t
*)other
)->encoding
);
202 if (!other
->get_encoding(other
, CERT_PGP_PKT
, &encoding
))
206 equal
= chunk_equals(this->encoding
, encoding
);
211 METHOD(certificate_t
, destroy
, void,
212 private_pgp_cert_t
*this)
214 if (ref_put(&this->ref
))
216 DESTROY_IF(this->key
);
217 DESTROY_IF(this->user_id
);
218 free(this->fingerprint
.ptr
);
219 free(this->encoding
.ptr
);
224 METHOD(pgp_certificate_t
, get_fingerprint
, chunk_t
,
225 private_pgp_cert_t
*this)
227 return this->fingerprint
;
233 private_pgp_cert_t
*create_empty()
235 private_pgp_cert_t
*this;
241 .get_type
= _get_type
,
242 .get_subject
= _get_subject
,
243 .get_issuer
= _get_issuer
,
244 .has_subject
= _has_subject
,
245 .has_issuer
= _has_issuer
,
246 .issued_by
= _issued_by
,
247 .get_public_key
= _get_public_key
,
248 .get_validity
= _get_validity
,
249 .get_encoding
= _get_encoding
,
254 .get_fingerprint
= _get_fingerprint
,
264 * Parse the public key packet of a PGP certificate
266 static bool parse_public_key(private_pgp_cert_t
*this, chunk_t packet
)
268 chunk_t pubkey_packet
= packet
;
270 if (!pgp_read_scalar(&packet
, 1, &this->version
))
274 switch (this->version
)
277 if (!pgp_read_scalar(&packet
, 4, &this->created
) ||
278 !pgp_read_scalar(&packet
, 2, &this->valid
))
284 if (!pgp_read_scalar(&packet
, 4, &this->created
))
290 DBG1(DBG_ASN
, "PGP packet version V%d not supported",
296 DBG2(DBG_ASN
, "L2 - created %T, valid %d days", &this->created
, FALSE
,
301 DBG2(DBG_ASN
, "L2 - created %T, never expires", &this->created
, FALSE
);
303 DESTROY_IF(this->key
);
304 this->key
= lib
->creds
->create(lib
->creds
, CRED_PUBLIC_KEY
, KEY_ANY
,
305 BUILD_BLOB_PGP
, packet
, BUILD_END
);
306 if (this->key
== NULL
)
311 /* compute V4 or V3 fingerprint according to section 12.2 of RFC 4880 */
312 if (this->version
== 4)
314 chunk_t pubkey_packet_header
= chunk_from_chars(
315 0x99, pubkey_packet
.len
/ 256, pubkey_packet
.len
% 256
319 hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_SHA1
);
322 DBG1(DBG_ASN
, "no SHA-1 hasher available");
325 if (!hasher
->allocate_hash(hasher
, pubkey_packet_header
, NULL
) ||
326 !hasher
->allocate_hash(hasher
, pubkey_packet
, &this->fingerprint
))
328 hasher
->destroy(hasher
);
331 hasher
->destroy(hasher
);
332 DBG2(DBG_ASN
, "L2 - v4 fingerprint %#B", &this->fingerprint
);
336 /* V3 fingerprint is computed by public_key_t class */
337 if (!this->key
->get_fingerprint(this->key
, KEYID_PGPV3
,
342 this->fingerprint
= chunk_clone(this->fingerprint
);
343 DBG2(DBG_ASN
, "L2 - v3 fingerprint %#B", &this->fingerprint
);
349 * Parse the signature packet of a PGP certificate
351 static bool parse_signature(private_pgp_cert_t
*this, chunk_t packet
)
353 uint32_t version
, len
, type
, created
;
355 if (!pgp_read_scalar(&packet
, 1, &version
))
360 /* we parse only v3 or v4 signature packets */
361 if (version
!= 3 && version
!= 4)
363 DBG2(DBG_ASN
, "L2 - v%d signature ignored", version
);
368 if (!pgp_read_scalar(&packet
, 1, &type
))
372 DBG2(DBG_ASN
, "L2 - v%d signature of type 0x%02x", version
, type
);
376 if (!pgp_read_scalar(&packet
, 1, &len
) || len
!= 5)
380 if (!pgp_read_scalar(&packet
, 1, &type
) ||
381 !pgp_read_scalar(&packet
, 4, &created
))
385 DBG2(DBG_ASN
, "L2 - v3 signature of type 0x%02x, created %T", type
,
388 /* TODO: parse and save signature to a list */
393 * Parse the userid packet of a PGP certificate
395 static bool parse_user_id(private_pgp_cert_t
*this, chunk_t packet
)
397 DESTROY_IF(this->user_id
);
398 this->user_id
= identification_create_from_encoding(ID_KEY_ID
, packet
);
399 DBG2(DBG_ASN
, "L2 - '%Y'", this->user_id
);
406 pgp_cert_t
*pgp_cert_load(certificate_type_t type
, va_list args
)
408 chunk_t packet
, blob
= chunk_empty
;
409 pgp_packet_tag_t tag
;
410 private_pgp_cert_t
*this;
414 switch (va_arg(args
, builder_part_t
))
417 blob
= va_arg(args
, chunk_t
);
427 this = create_empty();
428 this->encoding
= chunk_clone(blob
);
431 if (!pgp_read_packet(&blob
, &packet
, &tag
))
438 case PGP_PKT_PUBLIC_KEY
:
439 if (!parse_public_key(this, packet
))
445 case PGP_PKT_SIGNATURE
:
446 if (!parse_signature(this, packet
))
452 case PGP_PKT_USER_ID
:
453 if (!parse_user_id(this, packet
))
460 DBG1(DBG_LIB
, "ignoring %N packet in PGP certificate",
461 pgp_packet_tag_names
, tag
);
467 return &this->public;