/[winpt]/trunk/w32gpgme/keycache.c
ViewVC logotype

Contents of /trunk/w32gpgme/keycache.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 26 - (show annotations)
Mon Oct 17 08:49:30 2005 UTC (19 years, 4 months ago) by twoaday
File MIME type: text/plain
File size: 16003 byte(s)
More bug fixes all over the place.
See ChangeLog for details.

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26