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"
38 * Chained list of OpenPGP end certificates
40 static pgpcert_t
*pgpcerts
= NULL
;
45 #define PGP_KEYID_SIZE 8
47 const pgpcert_t pgpcert_empty
= {
52 { NULL
, 0 }, /* certificate */
55 NULL
, /* public key */
56 NULL
/* fingerprint */
61 * Extracts the length of a PGP packet
63 static size_t pgp_old_packet_length(chunk_t
*blob
)
65 /* bits 0 and 1 define the packet length type */
66 int len_type
= 0x03 & *blob
->ptr
++;
70 /* len_type: 0 -> 1 byte, 1 -> 2 bytes, 2 -> 4 bytes */
71 return pgp_length(blob
, (len_type
== 0)?
1: len_type
<< 1);
75 * Extracts PGP packet version (V3 or V4)
77 static u_char
pgp_version(chunk_t
*blob
)
79 u_char version
= *blob
->ptr
++;
82 DBG_log("L3 - version:");
83 DBG_log(" V%d", version
)
89 * Parse OpenPGP signature packet defined in section 5.2.2 of RFC 2440
91 static bool parse_pgp_signature_packet(chunk_t
*packet
, pgpcert_t
*cert
)
96 u_char version
= pgp_version(packet
);
98 /* we parse only V3 signature packets */
104 /* size byte must have the value 5 */
105 if (pgp_length(packet
, 1) != 5)
107 plog(" size must be 5");
111 /* signature type - 1 byte */
112 sig_type
= (u_char
)pgp_length(packet
, 1);
114 DBG_log("L3 - signature type: 0x%2x", sig_type
)
117 /* creation date - 4 bytes */
118 created
= (time_t)pgp_length(packet
, 4);
120 DBG_log("L3 - created:");
121 DBG_log(" %T", &cert
->created
, TRUE
)
124 /* key ID of signer - 8 bytes */
125 keyid
.ptr
= packet
->ptr
;
126 keyid
.len
= PGP_KEYID_SIZE
;
127 DBG_cond_dump_chunk(DBG_PARSING
, "L3 - key ID of signer", keyid
);
133 * Parses the version and validity of an OpenPGP public key packet
135 static bool parse_pgp_pubkey_version_validity(chunk_t
*packet
, pgpcert_t
*cert
)
137 cert
->version
= pgp_version(packet
);
139 if (cert
->version
< 3 || cert
->version
> 4)
141 plog("OpenPGP packet version V%d not supported", cert
->version
);
145 /* creation date - 4 bytes */
146 cert
->created
= (time_t)pgp_length(packet
, 4);
148 DBG_log("L3 - created:");
149 DBG_log(" %T", &cert
->created
, TRUE
)
152 if (cert
->version
== 3)
154 /* validity in days - 2 bytes */
155 cert
->until
= (time_t)pgp_length(packet
, 2);
157 /* validity of 0 days means that the key never expires */
160 cert
->until
= cert
->created
+ 24*3600*cert
->until
;
163 DBG_log("L3 - until:");
164 DBG_log(" %T", &cert
->until
, TRUE
);
171 * Parse OpenPGP public key packet defined in section 5.5.2 of RFC 4880
173 static bool parse_pgp_pubkey_packet(chunk_t
*packet
, pgpcert_t
*cert
)
175 pgp_pubkey_alg_t pubkey_alg
;
178 if (!parse_pgp_pubkey_version_validity(packet
, cert
))
183 /* public key algorithm - 1 byte */
184 pubkey_alg
= pgp_length(packet
, 1);
186 DBG_log("L3 - public key algorithm:");
187 DBG_log(" %N", pgp_pubkey_alg_names
, pubkey_alg
)
192 case PGP_PUBKEY_ALG_RSA
:
193 case PGP_PUBKEY_ALG_RSA_SIGN_ONLY
:
194 key
= lib
->creds
->create(lib
->creds
, CRED_PUBLIC_KEY
, KEY_RSA
,
195 BUILD_BLOB_PGP
, *packet
,
201 cert
->public_key
= key
;
203 if (cert
->version
== 3)
205 cert
->fingerprint
= key
->get_id(key
, ID_KEY_ID
);
206 if (cert
->fingerprint
== NULL
)
213 plog(" computation of V4 key ID not implemented yet");
218 plog(" non RSA public keys not supported");
225 * Parse OpenPGP secret key packet defined in section 5.5.3 of RFC 4880
227 static bool parse_pgp_secretkey_packet(chunk_t
*packet
, private_key_t
**key
)
229 pgp_pubkey_alg_t pubkey_alg
;
230 pgpcert_t cert
= pgpcert_empty
;
232 if (!parse_pgp_pubkey_version_validity(packet
, &cert
))
237 /* public key algorithm - 1 byte */
238 pubkey_alg
= pgp_length(packet
, 1);
240 DBG_log("L3 - public key algorithm:");
241 DBG_log(" %N", pgp_pubkey_alg_names
, pubkey_alg
)
246 case PGP_PUBKEY_ALG_RSA
:
247 case PGP_PUBKEY_ALG_RSA_SIGN_ONLY
:
248 *key
= lib
->creds
->create(lib
->creds
, CRED_PRIVATE_KEY
, KEY_RSA
,
249 BUILD_BLOB_PGP
, *packet
,
253 plog(" non RSA private keys not supported");
256 return (*key
!= NULL
);
259 bool parse_pgp(chunk_t blob
, pgpcert_t
*cert
, private_key_t
**key
)
262 DBG_log("L0 - PGP file:")
264 DBG_cond_dump_chunk(DBG_RAW
, "", blob
);
268 /* parse a PGP certificate file */
269 cert
->certificate
= blob
;
270 time(&cert
->installed
);
272 else if (key
== NULL
)
274 /* should not occur, nothing to parse */
280 chunk_t packet
= chunk_empty
;
281 u_char packet_tag
= *blob
.ptr
;
284 DBG_log("L1 - PGP packet: tag= 0x%2x", packet_tag
)
287 /* bit 7 must be set */
288 if (!(packet_tag
& 0x80))
290 plog(" incorrect Packet Tag");
294 /* bit 6 set defines new packet format */
295 if (packet_tag
& 0x40)
297 plog(" new PGP packet format not supported");
302 int packet_type
= (packet_tag
& 0x3C) >> 2;
304 packet
.len
= pgp_old_packet_length(&blob
);
305 packet
.ptr
= blob
.ptr
;
306 blob
.ptr
+= packet
.len
;
307 blob
.len
-= packet
.len
;
309 DBG_log(" %N (%d), old format, %u bytes",
310 pgp_packet_tag_names
, packet_type
,
311 packet_type
, packet
.len
);
312 DBG_log("L2 - body:")
314 DBG_cond_dump_chunk(DBG_RAW
, "", packet
);
318 /* parse a PGP certificate */
321 case PGP_PKT_PUBLIC_KEY
:
322 if (!parse_pgp_pubkey_packet(&packet
, cert
))
327 case PGP_PKT_SIGNATURE
:
328 if (!parse_pgp_signature_packet(&packet
, cert
))
333 case PGP_PKT_USER_ID
:
335 DBG_log("L3 - user ID:");
336 DBG_log(" '%.*s'", (int)packet
.len
, packet
.ptr
)
345 /* parse a PGP private key file */
348 case PGP_PKT_SECRET_KEY
:
349 if (!parse_pgp_secretkey_packet(&packet
, key
))
354 case PGP_PKT_USER_ID
:
356 DBG_log("L3 - user ID:");
357 DBG_log(" '%.*s'", (int)packet
.len
, packet
.ptr
)
371 * Compare two OpenPGP certificates
373 static bool same_pgpcert(pgpcert_t
*a
, pgpcert_t
*b
)
375 return a
->certificate
.len
== b
->certificate
.len
&&
376 memeq(a
->certificate
.ptr
, b
->certificate
.ptr
, b
->certificate
.len
);
380 * For each link pointing to the certificate increase the count by one
382 void share_pgpcert(pgpcert_t
*cert
)
391 * Select the OpenPGP keyid as ID
393 void select_pgpcert_id(pgpcert_t
*cert
, struct id
*end_id
)
395 end_id
->kind
= ID_KEY_ID
;
396 end_id
->name
= cert
->fingerprint
->get_encoding(cert
->fingerprint
);
400 * Add an OpenPGP user/host certificate to the chained list
402 pgpcert_t
* add_pgpcert(pgpcert_t
*cert
)
404 pgpcert_t
*c
= pgpcerts
;
408 if (same_pgpcert(c
, cert
)) /* already in chain, free cert */
416 /* insert new cert at the root of the chain */
417 cert
->next
= pgpcerts
;
419 DBG(DBG_CONTROL
| DBG_PARSING
,
420 DBG_log(" pgp cert inserted")
426 * Release of a certificate decreases the count by one.
427 * The certificate is freed when the counter reaches zero
429 void release_pgpcert(pgpcert_t
*cert
)
431 if (cert
!= NULL
&& --cert
->count
== 0)
433 pgpcert_t
**pp
= &pgpcerts
;
444 * Free a PGP certificate
446 void free_pgpcert(pgpcert_t
*cert
)
450 DESTROY_IF(cert
->public_key
);
451 DESTROY_IF(cert
->fingerprint
);
452 free(cert
->certificate
.ptr
);
458 * List all PGP end certificates in a chained list
460 void list_pgp_end_certs(bool utc
)
462 pgpcert_t
*cert
= pgpcerts
;
465 /* determine the current time */
470 whack_log(RC_COMMENT
, " ");
471 whack_log(RC_COMMENT
, "List of PGP End certificates:");
472 whack_log(RC_COMMENT
, " ");
477 public_key_t
*key
= cert
->public_key
;
483 whack_log(RC_COMMENT
, "%T, count: %d", &cert
->installed
, utc
, cert
->count
);
484 whack_log(RC_COMMENT
, " digest: %Y", cert
->fingerprint
);
485 whack_log(RC_COMMENT
, " created: %T", &cert
->created
, utc
);
486 whack_log(RC_COMMENT
, " until: %T %s", &cert
->until
, utc
,
487 check_expiry(cert
->until
, CA_CERT_WARNING_INTERVAL
, TRUE
));
488 whack_log(RC_COMMENT
, " pubkey: %N %4d bits%s",
489 key_type_names
, key
->get_type(key
),
490 key
->get_keysize(key
) * BITS_PER_BYTE
,
491 has_private_key(c
)?
", has private key" : "");
492 whack_log(RC_COMMENT
, " keyid: %Y",
493 key
->get_id(key
, ID_PUBKEY_INFO_SHA1
));