/[winpt]/trunk/Src/wptKeyCache.cpp
ViewVC logotype

Contents of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 28 - (show annotations)
Thu Oct 20 12:35:59 2005 UTC (19 years, 4 months ago) by twoaday
File size: 15698 byte(s)
Minor cleanups and prepare the translation.

1 /* wptKeyCache.cpp- Caching for the pub- and the secring
2 * Copyright (C) 2001-2005 Timo Schulz
3 *
4 * This file is part of MyGPGME.
5 *
6 * MyGPGME is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * MyGPGME is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 */
20 #include <windows.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <malloc.h>
24 #include <ctype.h>
25 #include <assert.h>
26
27 #include "w32gpgme.h"
28 #include "openpgp.h"
29 #include "wptNLS.h"
30 #include "wptErrors.h"
31
32
33 /* convert a binary buffer into its hex representation. */
34 static void
35 buffer_to_string (char *dst, size_t dlen, const byte *buf, size_t nbytes)
36 {
37 char dig[3];
38 size_t i;
39
40 memset (dst, 0, dlen);
41 for (i = 0; i < nbytes && dlen > 0; i++) {
42 sprintf (dig, "%02X", buf[i]);
43 strcat (dst, dig);
44 dlen -= 2;
45 }
46 }
47
48
49 /* Parse the secret keyring and retrieve some additional information
50 for each key which was found. */
51 static void
52 parse_secring (gpg_keycache_t cache, const char *kid, const char *secring)
53 {
54 PACKET *pkt = (PACKET*)calloc (1, sizeof *pkt);
55 PKT_secret_key *sk;
56 gpg_iobuf_t inp;
57 gpgme_error_t err;
58 gpgme_key_t key;
59 struct keycache_s *c=NULL;
60 char keyid[16+1];
61
62 inp = gpg_iobuf_open (secring);
63 if (!inp) {
64 safe_free (pkt);
65 return;
66 }
67 gpg_iobuf_ioctl (inp, 3, 1, NULL);
68 gpg_init_packet (pkt);
69 while (gpg_parse_packet (inp, pkt) != -1) {
70 if (pkt->pkttype == PKT_SECRET_KEY) {
71 sk = pkt->pkt.secret_key;
72 /* XXX: key IDs of card public keys are wrong! */
73 _snprintf (keyid, sizeof (keyid)-1, "%08lX",
74 gpg_keyid_from_sk (sk, NULL));
75 if (kid && strcmp (kid, keyid) != 0)
76 goto next;
77 err = gpg_keycache_find_key2 (cache, keyid, 0, &key, &c);
78 if (err)
79 goto next;
80 c->gloflags.is_protected = sk->is_protected;
81 c->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;
82 if (c->pubpart != NULL) {
83 c->pubpart->gloflags.is_protected = sk->is_protected;
84 c->pubpart->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;
85 }
86 }
87 next:
88 gpg_free_packet (pkt);
89 gpg_init_packet (pkt);
90 }
91 safe_free (pkt);
92 gpg_iobuf_close (inp);
93 }
94
95
96 /* Merge the information from the keyrings into the key cache structure. */
97 gpgme_error_t
98 keycache_prepare2 (gpg_keycache_t ctx, const char *kid,
99 const char *pubring, const char *secring)
100 {
101 gpgme_error_t err;
102 gpgme_key_t key = NULL;
103 gpg_iobuf_t inp;
104 PACKET *pkt = (PACKET*)calloc (1, sizeof * pkt);
105 struct keycache_s *c;
106 const byte *sym_prefs;
107 char keyid[16+1], *id = NULL;
108 int key_seen = 0;
109 size_t nbytes = 0, nsym =0;
110
111 if (secring) {
112 parse_secring (ctx, kid, secring);
113 if (!pubring) {
114 safe_free(pkt);
115 return 0;
116 }
117 }
118 inp = gpg_iobuf_open (pubring);
119 if (!inp) {
120 safe_free( pkt );
121 return gpg_error (GPG_ERR_KEYRING_OPEN);
122 }
123 gpg_iobuf_ioctl( inp, 3, 1, NULL ); /* disable cache */
124
125 gpg_init_packet( pkt );
126 while (gpg_parse_packet (inp, pkt) != -1) {
127 if (pkt->pkttype == PKT_PUBLIC_KEY) {
128 strcpy (keyid, "");
129 key_seen = 1;
130 }
131
132 if (pkt->pkttype == PKT_SIGNATURE && pkt->pkt.signature->sig_class == 0x1F) {
133 if (pkt->pkt.signature->numrevkeys == 0)
134 goto next;
135 _snprintf (keyid, sizeof keyid -1, "%08X", pkt->pkt.signature->keyid[1]);
136 if (kid && strcmp (kid, keyid) != 0)
137 goto next;
138 err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
139 if (err)
140 goto next;
141 c->gloflags.has_desig_rev = 1;
142 }
143 if (pkt->pkttype == PKT_SIGNATURE && key_seen == 1 ) {
144 sym_prefs=gpg_parse_sig_subpkt (pkt->pkt.signature->hashed,
145 SIGSUBPKT_PREF_SYM, &nsym);
146 if (sym_prefs == NULL)
147 goto next;
148 _snprintf (keyid, sizeof keyid - 1, "%08X", pkt->pkt.signature->keyid[1]);
149 if (kid && strcmp (kid, keyid) != 0)
150 goto next;
151 err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
152 if (err)
153 goto next;
154 else if (nsym > 0) {
155 c->sym_prefs = (unsigned char*)calloc (1, nsym+1);
156 if (!c->sym_prefs)
157 return gpg_error (GPG_ERR_ENOMEM);
158 memcpy (c->sym_prefs, sym_prefs, nsym);
159 }
160 }
161 if (pkt->pkttype == PKT_USER_ID) {
162 if (id)
163 free (id);
164 id = strdup (pkt->pkt.user_id->name);
165 if (!id) {
166 err = gpg_error (GPG_ERR_ENOMEM);
167 goto fail;
168 }
169 }
170 if ((pkt->pkttype == PKT_USER_ID || pkt->pkttype == PKT_ATTRIBUTE)
171 && pkt->pkt.user_id->attrib_data && key) {
172 PKT_user_id *id = pkt->pkt.user_id;
173 c->attrib.used = 1;
174 c->attrib.len = id->attrib_len;
175 c->attrib.d = (unsigned char*)calloc (1, id->attrib_len + 1);
176 if (!c->attrib.d) {
177 err = gpg_error (GPG_ERR_ENOMEM);
178 goto fail;
179 }
180 memcpy (c->attrib.d, id->attrib_data, id->attrib_len);
181 key = NULL;
182 c = NULL;
183 }
184 next:
185 gpg_free_packet (pkt);
186 gpg_init_packet(pkt);
187 }
188
189 fail:
190 safe_free (id);
191 safe_free (pkt);
192 gpg_iobuf_close (inp);
193 return err;
194 }
195
196
197 gpgme_error_t
198 gpg_keycache_prepare (gpg_keycache_t ctx, const char *pubr, const char *secr)
199 {
200 return keycache_prepare2 (ctx, NULL, pubr, secr);
201 }
202
203 gpgme_error_t
204 gpg_keycache_prepare_single (gpg_keycache_t ctx, const char *keyid,
205 const char *pubr, const char *secr)
206 {
207 if (!strncmp (keyid, "0x", 2))
208 keyid += 2;
209 return keycache_prepare2 (ctx, keyid, pubr, secr);
210 }
211
212
213 /* Create new keycache object and return it in @r_ctx.
214 Return value: 0 on success. */
215 gpgme_error_t
216 gpg_keycache_new (gpg_keycache_t *r_ctx)
217 {
218 gpg_keycache_t ctx;
219
220 if (!r_ctx)
221 return gpg_error (GPG_ERR_INV_ARG);
222 ctx = (gpg_keycache_t)calloc (1, sizeof *ctx);
223 if (!ctx)
224 return gpg_error (GPG_ERR_ENOMEM);
225 ctx->secret = 0;
226 ctx->pos = 0;
227 *r_ctx = ctx;
228 return 0;
229 }
230
231
232 /* Release keycache object @ctx. */
233 void
234 gpg_keycache_release (gpg_keycache_t ctx)
235 {
236 struct keycache_s *c, *c2;
237
238 if (!ctx)
239 return;
240
241 for (c = ctx->item; c; c = c2) {
242 c2 = c->next;
243 gpgme_key_release (c->key);
244 c->key = NULL;
245 if (c->sym_prefs)
246 free (c->sym_prefs);
247 c->sym_prefs = NULL;
248 if (c->attrib.d)
249 free (c->attrib.d);
250 c->attrib.d = NULL;
251 if (c->card_type)
252 free (c->card_type);
253 free (c);
254 }
255 if (ctx)
256 free (ctx);
257 }
258
259
260 /* Set (progress) callback for the given keycache object.
261 @ctx the keycache
262 @cb the callback function
263 @cb_value1 opaque value which is passed to the callback.
264 @cb_value2 see @cb_value1. */
265 void
266 gpg_keycache_set_cb (gpg_keycache_t ctx,
267 void (*cb)(void *, const char *, int, int, int),
268 void * cb_value1, int cb_value2)
269 {
270 if (!ctx)
271 return;
272 ctx->cb = cb;
273 ctx->cb_value = cb_value1;
274 ctx->cb_value2 = cb_value2;
275 }
276
277
278 /* Add @key to the cache @ctx. @opaque return the key cache context as a void*.
279 Return value: 0 on success. */
280 gpgme_error_t
281 gpg_keycache_add_key (gpg_keycache_t ctx, gpgme_key_t key, void **opaque)
282 {
283 struct keycache_s * c, * n1;
284
285 if (!ctx)
286 return gpg_error (GPG_ERR_INV_ARG);
287
288 c = (struct keycache_s*)calloc (1, sizeof *c);
289 if (!c)
290 return gpg_error (GPG_ERR_ENOMEM);
291 c->gloflags.is_protected = 1; /*default: assume protection. */
292 c->key = key;
293 if (!ctx->item)
294 ctx->item = c;
295 else {
296 for (n1 = ctx->item; n1 && n1->next; n1 = n1->next)
297 ;
298 n1->next = c;
299 }
300 if (opaque)
301 *opaque = c;
302 return 0;
303 }
304
305
306
307 #define has_keyid_len(pattern) (\
308 strlen (pattern) == 8 || strlen (pattern) == 10 || \
309 strlen (pattern) == 16 || strlen (pattern) == 18)
310
311
312 gpgme_error_t
313 gpg_keycache_find_key2 (gpg_keycache_t ctx, const char *pattern, int flags,
314 gpgme_key_t *r_key, struct keycache_s **r_item)
315 {
316 struct keycache_s *c;
317 gpgme_subkey_t s;
318 gpgme_user_id_t u;
319 gpgme_key_t key;
320 const char *kid;
321
322 if (!ctx || !r_key)
323 return gpg_error (GPG_ERR_INV_ARG);
324
325 if (strstr (pattern, "0x"))
326 pattern += 2;
327
328 /* Sometimes a subkey has no valid fpr. As a kludge we convert v4
329 fingerprints into the 64-bit keyid. */
330 if (strlen (pattern) == 40 && isxdigit (*pattern))
331 pattern += 32;
332
333 /* XXX: this code is very slow, revamp it and use hash tables whenever
334 it is possible. */
335 for (c = ctx->item; c; c = c->next) {
336 key = c->key;
337 assert (key->_refs >= 1);
338 for (s = key->subkeys; s; s = s->next) {
339 for (u = key->uids; u; u = u->next) {
340 if (u->name && stristr (u->name, pattern)) {
341 if (r_item)
342 *r_item = c;
343 *r_key = flags? c->pubpart->key : c->key;
344 return 0;
345 }
346 }
347 if (has_keyid_len (pattern))
348 kid = s->keyid;
349 else
350 kid = s->fpr;
351 if (kid && stristr (kid, pattern)) {
352 if (r_item)
353 *r_item = c;
354 *r_key = flags? c->pubpart->key : c->key;
355 return 0;
356 }
357 }
358 }
359 *r_key = NULL;
360 return gpg_error (GPG_ERR_INTERNAL);
361 } /* keycache_find_key */
362
363
364 gpgme_error_t
365 gpg_keycache_find_key (gpg_keycache_t ctx, const char *pattern,
366 int flags, gpgme_key_t *r_key)
367 {
368 return gpg_keycache_find_key2 (ctx, pattern, flags, r_key, NULL);
369 }
370
371
372 gpgme_error_t
373 gpg_keycache_update_key (gpg_keycache_t ctx, int is_sec,
374 void *opaque, const char *keyid)
375 {
376 struct keycache_s *c = NULL, *c_new=NULL;
377 gpgme_key_t key=NULL, fndkey=NULL;
378 gpgme_error_t err;
379 gpgme_ctx_t gctx;
380 gpg_keycache_t pub = (gpg_keycache_t)opaque;
381
382 err = gpgme_new (&gctx);
383 if (err)
384 return err;
385 err = gpgme_get_key (gctx, keyid, &key, is_sec);
386 gpgme_release (gctx);
387 if (err)
388 return err;
389 err = gpg_keycache_find_key2 (ctx, keyid, 0, &fndkey, &c);
390 if (!err && c != NULL) {
391 log_debug ("keycache update: keyid=%s %p\r\n", keyid, pub);
392 gpgme_key_release (fndkey);
393 c->key = key;
394 c->flags = 0;
395 if (is_sec && pub != NULL &&
396 !gpg_keycache_find_key (pub, keyid, 0, &fndkey)) {
397 log_debug ("keycache update: set public part %p\r\n", fndkey);
398 c->pubpart->key = fndkey;
399 }
400 }
401 else {
402 log_debug ("keycache add: sync public part\r\n");
403 if (is_sec)
404 gpg_keycache_find_key2 (pub, keyid, 0, &fndkey, &c_new);
405 gpg_keycache_add_key (ctx, key, (void **)&c);
406 if (c != NULL && is_sec) {
407 log_debug ("keycache add: keyid=%s %p %p\r\n", keyid, c, fndkey);
408 c->pubpart = c_new;
409 if (c_new != NULL) {
410 c->pubpart->key = fndkey;
411 c->gloflags.is_protected = c_new->gloflags.is_protected;
412 c->gloflags.divert_to_card = c_new->gloflags.divert_to_card;
413 }
414 }
415 }
416 return 0;
417 }
418
419
420 /* Delete a key from the cache @ctx with the pattern @pattern.
421 Return value: 0 on success. */
422 gpgme_error_t
423 gpg_keycache_delete_key (gpg_keycache_t ctx, const char *pattern)
424 {
425 struct keycache_s *itm = NULL, *c;
426 gpgme_key_t key;
427 gpgme_error_t rc;
428
429 if (!ctx)
430 return gpg_error (GPG_ERR_INV_ARG);
431 rc = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);
432 if (rc)
433 return rc;
434
435 c = ctx->item;
436 if (c->next == NULL) {
437 gpgme_key_release (itm->key);
438 if (itm)
439 free (itm);
440 ctx->item = NULL;
441 }
442 else {
443 while (c && c->next != itm)
444 c = c->next;
445 c->next = c->next->next;
446 gpgme_key_release (itm->key);
447 if (itm)
448 free (itm);
449 }
450 return 0;
451 }
452
453
454 /* Initialize the given cache @ctx. If @pattern is NULL, the entire keyring
455 will be added to the cache. @secret is 1 if the source is the secret keyring.
456 Return value: 0 on success. */
457 gpgme_error_t
458 gpg_keycache_init (gpg_keycache_t ctx, const char *pattern, int secret)
459 {
460 gpgme_error_t err;
461 gpgme_ctx_t c;
462 gpgme_key_t key;
463 int count = 0;
464
465 if (!ctx)
466 return gpg_error (GPG_ERR_INV_ARG);
467
468 err = gpgme_new (&c);
469 if (err)
470 return err;
471
472 gpgme_set_keylist_mode (c, GPGME_KEYLIST_MODE_SIGS);
473 err = gpgme_op_keylist_start (c, pattern, secret);
474 while(!err) {
475 err = gpgme_op_keylist_next (c, &key);
476 if (!err)
477 err = gpg_keycache_add_key (ctx, key, NULL);
478 if (ctx->cb)
479 ctx->cb (ctx->cb_value, _("Load GPG Keyrings..."), 0,
480 count++, ctx->cb_value2);
481 }
482 if (gpgme_err_code (err) == GPG_ERR_EOF)
483 err = gpg_error (GPG_ERR_NO_ERROR);
484 /* XXX: make sure the progress dialog is closed. */
485 gpgme_op_keylist_end (c);
486 gpgme_release (c);
487 return err;
488 }
489
490
491 /* XXX: kludge to see if the key is stored on a card. */
492 static int
493 key_divert_to_card (gpgme_key_t key)
494 {
495 gpgme_subkey_t k;
496 int n=0, n_alg=0, can_auth = 0;
497
498 for (k = key->subkeys; k; k = k->next) {
499 n++;
500 if (k->pubkey_algo == GPGME_PK_RSA && k->length == 1024)
501 n_alg++;
502 if (k->can_authenticate)
503 can_auth++;
504 }
505 if (n == 3 && n_alg == 3 && can_auth == 1)
506 return 1;
507 return 0;
508 }
509
510
511 gpgme_error_t
512 gpg_keycache_sync (gpg_keycache_t pub, gpg_keycache_t sec)
513 {
514 struct keycache_s *c, *c_sec;
515 gpgme_key_t key;
516
517 if (!pub || !sec)
518 return gpg_error (GPG_ERR_INV_ARG);
519
520 for (c=sec->item; c; c=c->next) {
521 if (!gpg_keycache_find_key2 (pub, c->key->subkeys->keyid, 0, &key, &c_sec)) {
522 c_sec->gloflags.is_protected = c->gloflags.is_protected;
523 c_sec->gloflags.divert_to_card = c->gloflags.divert_to_card;
524 if (!c->gloflags.divert_to_card)
525 c->gloflags.divert_to_card = key_divert_to_card (key);
526 c->pubpart = c_sec;
527 c->pubpart->key = key;
528 }
529 }
530 return 0;
531 }
532
533
534 /* Rewind the given cache @ctx to the begin. */
535 void
536 gpg_keycache_rewind (gpg_keycache_t ctx)
537 {
538 if (ctx)
539 ctx->pos = 0;
540 }
541
542
543
544 /* Return the number of elements in the cache @ctx. */
545 int
546 gpg_keycache_get_size (gpg_keycache_t ctx)
547 {
548 struct keycache_s *c;
549 int count = 0;
550
551 if (!ctx)
552 return 0;
553 for (c = ctx->item; c; c = c->next)
554 count++;
555 return count;
556 }
557
558
559 static gpgme_error_t
560 keycache_next_key (gpg_keycache_t ctx, int flags,
561 struct keycache_s **c, gpgme_key_t *r_key)
562 {
563 if (!ctx || !r_key)
564 return gpg_error (GPG_ERR_INV_ARG);
565
566 if (!ctx->pos)
567 ctx->tmp = ctx->item;
568
569 if (!ctx->tmp || !ctx->tmp->key) {
570 ctx->pos = 0;
571 *r_key = NULL;
572 return gpg_error (GPG_ERR_EOF);
573 }
574
575 *r_key = flags? ctx->tmp->pubpart->key : ctx->tmp->key;
576 *c = ctx->tmp = ctx->tmp->next;
577 ctx->pos++;
578
579 return 0;
580 }
581
582
583 /* Return the next key from the cache @ctx. The key will be returned
584 in @r_key. @flags can contain additional flags.
585 Return value: 0 on success. */
586 gpgme_error_t
587 gpg_keycache_next_key (gpg_keycache_t ctx, int flags, gpgme_key_t *r_key)
588 {
589 struct keycache_s *c=NULL;
590 gpgme_error_t err = 0;
591
592 err = keycache_next_key (ctx, flags, &c, r_key);
593 return err;
594 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26