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

Annotation of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (hide annotations)
Mon Oct 24 08:03:48 2005 UTC (19 years, 4 months ago) by twoaday
File size: 15748 byte(s)
2005-10-23  Timo Schulz  <twoaday@g10code.com>
 
        * wptFileManager.cpp (fm_get_file_type): Detect detached sigs.
        * wptKeyList.cpp (keylist_cmp_cb): Take care of expired/revoked keys.
        (get_ext_validity): New.
        * wptFileVerifyDlg.cpp (file_verify_dlg_proc): Several cleanups.
        * wptClipEditDlg.cpp (load_clipboard): Factored out some code into
        this function.
        (load_clipboard_from_file): Likewise.
        (save_clipboard_to_file): New.
        * wptKeyManagerDlg.cpp (keyprops_dlg_proc): Fix stack overflow.

For complete details, see the ChangeLog files.

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26