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

Annotation of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 42 - (hide annotations)
Fri Oct 28 08:25:30 2005 UTC (19 years, 4 months ago) by werner
File size: 15220 byte(s)
Readded lost changes from revision 40

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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26