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

Annotation of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 28 - (hide 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 twoaday 28 /* 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