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

Annotation of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 48 - (hide annotations)
Mon Oct 31 21:14:11 2005 UTC (19 years, 4 months ago) by werner
File size: 15199 byte(s)
More changes.  Compiles again but there are at least gettext issues with
w32-gettext.c.  I can't get a gpg-error build with ENABLE_NLS.

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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26