5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2007 - 2008 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
20 #include "silccrypto.h"
24 /************************ Static utility functions **************************/
26 /* Computes fingerprint of the OpenPGP public key and saves it to the key.
27 Saves also the key IDs to public key context. */
29 static SilcBool silc_pgp_compute_fingerprint(SilcBuffer keybuf,
30 SilcPGPPublicKey pubkey)
32 SILC_LOG_DEBUG(("Computing fingerprint"));
34 if (pubkey->version >= 4) {
39 if (!silc_hash_alloc("sha1", &sha1))
43 SILC_PUT16_MSB(silc_buffer_len(keybuf), tmp + 1);
46 silc_hash_update(sha1, tmp, 3);
47 silc_hash_update(sha1, silc_buffer_data(keybuf), silc_buffer_len(keybuf));
48 silc_hash_final(sha1, pubkey->fingerprint);
52 memcpy(pubkey->key_id, pubkey->fingerprint + 12, 8);
54 /* Versions 2 and 3 */
57 SilcUInt16 n_len, e_len;
59 if (!silc_hash_alloc("md5", &md5))
62 silc_buffer_format(keybuf,
64 SILC_STR_UI16_NSTRING(&n, &n_len),
65 SILC_STR_UI16_NSTRING(&e, &e_len),
68 n_len = (n_len + 7) / 8;
69 e_len = (e_len + 7) / 8;
72 silc_hash_update(md5, n, n_len);
73 silc_hash_update(md5, e, e_len);
74 silc_hash_final(md5, pubkey->fingerprint);
78 memcpy(pubkey->key_id, n + (n_len - 8), 8);
84 /*************************** Public Key Routines ****************************/
86 /* Decode OpenPGP Public Key packet */
88 int silc_pgp_packet_public_key_decode(unsigned char *key, SilcUInt32 key_len,
89 SilcPGPPublicKey pubkey)
91 SilcBufferStruct keybuf, fbuf;
92 const SilcPKCSAlgorithm *pkcs;
95 SILC_LOG_DEBUG(("Parse OpenPGP public key packet"));
99 silc_buffer_set(&keybuf, key, key_len);
101 SILC_LOG_HEXDUMP(("OpenPGP public key"), key, key_len);
104 if (silc_buffer_unformat(&keybuf,
106 SILC_STR_UINT8(&pubkey->version),
107 SILC_STR_UI_INT(&pubkey->created),
109 SILC_LOG_DEBUG(("Malformed public key"));
113 if (pubkey->version < 2) {
114 SILC_LOG_DEBUG(("Invalid version %d", pubkey->version));
118 SILC_LOG_DEBUG(("Public key version %d", pubkey->version));
120 if (pubkey->version <= 3) {
121 /* Versions 2 and 3 */
122 if (silc_buffer_unformat(&keybuf,
124 SILC_STR_UINT16(&pubkey->valid),
125 SILC_STR_UINT8(&pubkey->algorithm),
127 SILC_LOG_DEBUG(("Malformed public key"));
132 if (silc_buffer_unformat(&keybuf,
134 SILC_STR_UINT8(&pubkey->algorithm),
136 SILC_LOG_DEBUG(("Malformed public key"));
141 SILC_LOG_DEBUG(("Parse algorithm %d", pubkey->algorithm));
143 /* Decode the public key algorithm */
144 switch (pubkey->algorithm) {
145 case SILC_PGP_PKCS_RSA:
146 case SILC_PGP_PKCS_RSA_ENC_ONLY:
147 case SILC_PGP_PKCS_RSA_SIG_ONLY:
148 /* Get PKCS object */
149 pkcs = silc_pkcs_find_algorithm("rsa", "openpgp");
151 SILC_LOG_ERROR(("Unsupported PKCS algorithm (rsa/openpgp)"));
156 case SILC_PGP_PKCS_DSA:
157 /* Get PKCS object */
158 pkcs = silc_pkcs_find_algorithm("dsa", "openpgp");
160 SILC_LOG_ERROR(("Unsupported PKCS algorithm (dsa/openpgp)"));
165 case SILC_PGP_PKCS_ELGAMAL_ENC_ONLY:
166 case SILC_PGP_PKCS_ELGAMAL:
167 /* Get PKCS object */
168 pkcs = silc_pkcs_find_algorithm("elgamal", "openpgp");
170 SILC_LOG_ERROR(("Unsupported PKCS algorithm (elgamal/openpgp)"));
176 SILC_LOG_DEBUG(("Unsupported OpenPGP public key algorithm %d",
182 /* Import the algorithm public key */
183 ret = pkcs->import_public_key(pkcs, silc_buffer_data(&keybuf),
184 silc_buffer_len(&keybuf),
185 &pubkey->public_key);
187 SILC_LOG_DEBUG(("Malformed public key"));
191 /* Compute and save fingerprint */
192 silc_buffer_set(&fbuf, key, silc_buffer_headlen(&keybuf) + ret);
193 if (!silc_pgp_compute_fingerprint(&fbuf, pubkey))
196 return silc_buffer_headlen(&keybuf) + ret;
202 /* Decode public key from PGP packets */
204 SilcBool silc_pgp_public_key_decode(SilcList *list,
205 SilcPGPPublicKey *ret_public_key)
207 SilcPGPPublicKey pubkey, subkey;
210 SilcPGPPacket pub, packet;
212 SILC_LOG_DEBUG(("Parse OpenPGP public key"));
214 pubkey = silc_calloc(1, sizeof(*pubkey));
218 /* First packet must be public key packet */
219 pub = silc_list_get(*list);
222 if (silc_pgp_packet_get_tag(pub) != SILC_PGP_PACKET_PUBKEY &&
223 silc_pgp_packet_get_tag(pub) != SILC_PGP_PACKET_PUBKEY_SUB)
226 /* Parse the public key */
227 data = silc_pgp_packet_get_data(pub, &data_len);
228 if (!silc_pgp_packet_public_key_decode(data, data_len, pubkey))
231 /* Parse any and all packets until we hit end of the packets or next
232 public key in the list. We simply copy the raw data, and actual
233 parsing is done later if and when the packets are needed. */
234 if (silc_pgp_packet_get_tag(pub) == SILC_PGP_PACKET_PUBKEY) {
235 silc_list_init(pubkey->packets, struct SilcPGPPacketStruct, next);
237 /* Copy the raw public key packet */
238 packet = silc_pgp_packet_copy(pub);
240 silc_list_add(pubkey->packets, packet);
242 while ((packet = silc_list_get(*list))) {
243 SILC_LOG_DEBUG(("Adding %d (%s) packet to public key",
244 silc_pgp_packet_get_tag(packet),
245 silc_pgp_packet_name(silc_pgp_packet_get_tag(packet))));
247 switch (silc_pgp_packet_get_tag(packet)) {
249 case SILC_PGP_PACKET_PUBKEY:
250 /* Next public key, stop decoding. Set list pointer so that the list
251 points to the next public key. */
252 list->current = packet;
255 case SILC_PGP_PACKET_PUBKEY_SUB:
256 /* Parse subkeys recursively */
257 list->current = packet;
258 if (!silc_pgp_public_key_decode(list, &subkey))
261 if (!pubkey->subkeys) {
262 pubkey->subkeys = silc_dlist_init();
263 if (!pubkey->subkeys)
266 silc_dlist_add(pubkey->subkeys, subkey);
269 /* Copy packet to the public key */
270 packet = silc_pgp_packet_copy(packet);
272 silc_list_add(pubkey->packets, packet);
279 *ret_public_key = pubkey;
288 /* Free public key */
290 void silc_pgp_public_key_free(SilcPGPPublicKey public_key)
293 SilcPGPPacket packet;
295 if (public_key->pkcs)
296 public_key->pkcs->public_key_free(public_key->pkcs,
297 public_key->public_key);
299 if (public_key->subkeys) {
300 silc_dlist_start(public_key->subkeys);
301 while ((p = silc_dlist_get(public_key->subkeys)))
302 silc_pgp_public_key_free(p);
303 silc_dlist_uninit(public_key->subkeys);
306 silc_list_start(public_key->packets);
307 while ((packet = silc_list_get(public_key->packets)))
308 silc_pgp_packet_free(packet);
310 silc_free(public_key);