1 /* Support of OpenPGP certificates
2 * Copyright (C) 2002-2009 Andreas Steffen
4 * HSR - Hochschule fuer Technik Rapperswil
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
25 #include <crypto/hashers/hasher.h>
27 #include "constants.h"
37 * Chained list of OpenPGP end certificates
39 static pgpcert_t
*pgpcerts
= NULL
;
44 #define PGP_KEYID_SIZE 8
46 const pgpcert_t pgpcert_empty
= {
51 { NULL
, 0 }, /* certificate */
54 NULL
, /* public key */
55 NULL
/* fingerprint */
60 * Extracts the length of a PGP packet
62 static size_t pgp_old_packet_length(chunk_t
*blob
)
64 /* bits 0 and 1 define the packet length type */
65 int len_type
= 0x03 & *blob
->ptr
++;
69 /* len_type: 0 -> 1 byte, 1 -> 2 bytes, 2 -> 4 bytes */
70 return pgp_length(blob
, (len_type
== 0)?
1: len_type
<< 1);
74 * Extracts PGP packet version (V3 or V4)
76 static u_char
pgp_version(chunk_t
*blob
)
78 u_char version
= *blob
->ptr
++;
81 DBG_log("L3 - version:");
82 DBG_log(" V%d", version
)
88 * Parse OpenPGP signature packet defined in section 5.2.2 of RFC 2440
90 static bool parse_pgp_signature_packet(chunk_t
*packet
, pgpcert_t
*cert
)
95 u_char version
= pgp_version(packet
);
97 /* we parse only V3 signature packets */
103 /* size byte must have the value 5 */
104 if (pgp_length(packet
, 1) != 5)
106 plog(" size must be 5");
110 /* signature type - 1 byte */
111 sig_type
= (u_char
)pgp_length(packet
, 1);
113 DBG_log("L3 - signature type: 0x%2x", sig_type
)
116 /* creation date - 4 bytes */
117 created
= (time_t)pgp_length(packet
, 4);
119 DBG_log("L3 - created:");
120 DBG_log(" %T", &cert
->created
, TRUE
)
123 /* key ID of signer - 8 bytes */
124 keyid
.ptr
= packet
->ptr
;
125 keyid
.len
= PGP_KEYID_SIZE
;
126 DBG_cond_dump_chunk(DBG_PARSING
, "L3 - key ID of signer", keyid
);
132 * Parses the version and validity of an OpenPGP public key packet
134 static bool parse_pgp_pubkey_version_validity(chunk_t
*packet
, pgpcert_t
*cert
)
136 cert
->version
= pgp_version(packet
);
138 if (cert
->version
< 3 || cert
->version
> 4)
140 plog("OpenPGP packet version V%d not supported", cert
->version
);
144 /* creation date - 4 bytes */
145 cert
->created
= (time_t)pgp_length(packet
, 4);
147 DBG_log("L3 - created:");
148 DBG_log(" %T", &cert
->created
, TRUE
)
151 if (cert
->version
== 3)
153 /* validity in days - 2 bytes */
154 cert
->until
= (time_t)pgp_length(packet
, 2);
156 /* validity of 0 days means that the key never expires */
159 cert
->until
= cert
->created
+ 24*3600*cert
->until
;
162 DBG_log("L3 - until:");
163 DBG_log(" %T", &cert
->until
, TRUE
);
170 * Parse OpenPGP public key packet defined in section 5.5.2 of RFC 4880
172 static bool parse_pgp_pubkey_packet(chunk_t
*packet
, pgpcert_t
*cert
)
174 pgp_pubkey_alg_t pubkey_alg
;
177 if (!parse_pgp_pubkey_version_validity(packet
, cert
))
182 /* public key algorithm - 1 byte */
183 pubkey_alg
= pgp_length(packet
, 1);
185 DBG_log("L3 - public key algorithm:");
186 DBG_log(" %N", pgp_pubkey_alg_names
, pubkey_alg
)
191 case PGP_PUBKEY_ALG_RSA
:
192 case PGP_PUBKEY_ALG_RSA_SIGN_ONLY
:
193 key
= lib
->creds
->create(lib
->creds
, CRED_PUBLIC_KEY
, KEY_RSA
,
194 BUILD_BLOB_PGP
, *packet
,
200 cert
->public_key
= key
;
202 if (cert
->version
== 3)
204 cert
->fingerprint
= key
->get_id(key
, ID_KEY_ID
);
205 if (cert
->fingerprint
== NULL
)
212 plog(" computation of V4 key ID not implemented yet");
217 plog(" non RSA public keys not supported");
224 * Parse OpenPGP secret key packet defined in section 5.5.3 of RFC 4880
226 static bool parse_pgp_secretkey_packet(chunk_t
*packet
, private_key_t
**key
)
228 pgp_pubkey_alg_t pubkey_alg
;
229 pgpcert_t cert
= pgpcert_empty
;
231 if (!parse_pgp_pubkey_version_validity(packet
, &cert
))
236 /* public key algorithm - 1 byte */
237 pubkey_alg
= pgp_length(packet
, 1);
239 DBG_log("L3 - public key algorithm:");
240 DBG_log(" %N", pgp_pubkey_alg_names
, pubkey_alg
)
245 case PGP_PUBKEY_ALG_RSA
:
246 case PGP_PUBKEY_ALG_RSA_SIGN_ONLY
:
247 *key
= lib
->creds
->create(lib
->creds
, CRED_PRIVATE_KEY
, KEY_RSA
,
248 BUILD_BLOB_PGP
, *packet
,
252 plog(" non RSA private keys not supported");
255 return (*key
!= NULL
);
258 bool parse_pgp(chunk_t blob
, pgpcert_t
*cert
, private_key_t
**key
)
261 DBG_log("L0 - PGP file:")
263 DBG_cond_dump_chunk(DBG_RAW
, "", blob
);
267 /* parse a PGP certificate file */
268 cert
->certificate
= blob
;
269 time(&cert
->installed
);
271 else if (key
== NULL
)
273 /* should not occur, nothing to parse */
279 chunk_t packet
= chunk_empty
;
280 u_char packet_tag
= *blob
.ptr
;
283 DBG_log("L1 - PGP packet: tag= 0x%2x", packet_tag
)
286 /* bit 7 must be set */
287 if (!(packet_tag
& 0x80))
289 plog(" incorrect Packet Tag");
293 /* bit 6 set defines new packet format */
294 if (packet_tag
& 0x40)
296 plog(" new PGP packet format not supported");
301 int packet_type
= (packet_tag
& 0x3C) >> 2;
303 packet
.len
= pgp_old_packet_length(&blob
);
304 packet
.ptr
= blob
.ptr
;
305 blob
.ptr
+= packet
.len
;
306 blob
.len
-= packet
.len
;
308 DBG_log(" %N (%d), old format, %u bytes",
309 pgp_packet_tag_names
, packet_type
,
310 packet_type
, packet
.len
);
311 DBG_log("L2 - body:")
313 DBG_cond_dump_chunk(DBG_RAW
, "", packet
);
317 /* parse a PGP certificate */
320 case PGP_PKT_PUBLIC_KEY
:
321 if (!parse_pgp_pubkey_packet(&packet
, cert
))
326 case PGP_PKT_SIGNATURE
:
327 if (!parse_pgp_signature_packet(&packet
, cert
))
332 case PGP_PKT_USER_ID
:
334 DBG_log("L3 - user ID:");
335 DBG_log(" '%.*s'", (int)packet
.len
, packet
.ptr
)
344 /* parse a PGP private key file */
347 case PGP_PKT_SECRET_KEY
:
348 if (!parse_pgp_secretkey_packet(&packet
, key
))
353 case PGP_PKT_USER_ID
:
355 DBG_log("L3 - user ID:");
356 DBG_log(" '%.*s'", (int)packet
.len
, packet
.ptr
)
370 * Compare two OpenPGP certificates
372 static bool same_pgpcert(pgpcert_t
*a
, pgpcert_t
*b
)
374 return a
->certificate
.len
== b
->certificate
.len
&&
375 memeq(a
->certificate
.ptr
, b
->certificate
.ptr
, b
->certificate
.len
);
379 * For each link pointing to the certificate increase the count by one
381 void share_pgpcert(pgpcert_t
*cert
)
390 * Select the OpenPGP keyid as ID
392 void select_pgpcert_id(pgpcert_t
*cert
, struct id
*end_id
)
394 end_id
->kind
= ID_KEY_ID
;
395 end_id
->name
= cert
->fingerprint
->get_encoding(cert
->fingerprint
);
399 * Add an OpenPGP user/host certificate to the chained list
401 pgpcert_t
* add_pgpcert(pgpcert_t
*cert
)
403 pgpcert_t
*c
= pgpcerts
;
407 if (same_pgpcert(c
, cert
)) /* already in chain, free cert */
415 /* insert new cert at the root of the chain */
416 cert
->next
= pgpcerts
;
418 DBG(DBG_CONTROL
| DBG_PARSING
,
419 DBG_log(" pgp cert inserted")
425 * Release of a certificate decreases the count by one.
426 * The certificate is freed when the counter reaches zero
428 void release_pgpcert(pgpcert_t
*cert
)
430 if (cert
!= NULL
&& --cert
->count
== 0)
432 pgpcert_t
**pp
= &pgpcerts
;
443 * Free a PGP certificate
445 void free_pgpcert(pgpcert_t
*cert
)
449 DESTROY_IF(cert
->public_key
);
450 DESTROY_IF(cert
->fingerprint
);
451 free(cert
->certificate
.ptr
);
457 * List all PGP end certificates in a chained list
459 void list_pgp_end_certs(bool utc
)
461 pgpcert_t
*cert
= pgpcerts
;
464 /* determine the current time */
469 whack_log(RC_COMMENT
, " ");
470 whack_log(RC_COMMENT
, "List of PGP End certificates:");
471 whack_log(RC_COMMENT
, " ");
476 public_key_t
*key
= cert
->public_key
;
482 whack_log(RC_COMMENT
, "%T, count: %d", &cert
->installed
, utc
, cert
->count
);
483 whack_log(RC_COMMENT
, " digest: %Y", cert
->fingerprint
);
484 whack_log(RC_COMMENT
, " created: %T", &cert
->created
, utc
);
485 whack_log(RC_COMMENT
, " until: %T %s", &cert
->until
, utc
,
486 check_expiry(cert
->until
, CA_CERT_WARNING_INTERVAL
, TRUE
));
487 whack_log(RC_COMMENT
, " pubkey: %N %4d bits%s",
488 key_type_names
, key
->get_type(key
),
489 key
->get_keysize(key
) * BITS_PER_BYTE
,
490 has_private_key(c
)?
", has private key" : "");
491 whack_log(RC_COMMENT
, " keyid: %Y",
492 key
->get_id(key
, ID_PUBKEY_INFO_SHA1
));