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

Annotation of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 123 - (hide annotations)
Wed Dec 14 09:01:45 2005 UTC (19 years, 2 months ago) by twoaday
File size: 15544 byte(s)
2005-12-13  Timo Schulz  <ts@g10code.com>
 
        * wptCommonDlg.cpp (http_dlg_proc): Localized missing elements.
        * wptKeyManagerDlg.cpp (change_edit_menu): New.
        (change_key_menu): Renamed from...
        (menu_gpg_readonly): ..this.
        (clip_contains_pgpkey): New.
        (update_ui_items): Do not allow to sign expired keys.
        (keymanager_dlg_proc): Same for popup menu.
        * wptKeyPropsDlg.cpp (parse_preflist): Fixed string handling.
        * wptKeyCache.cpp (copy_uid_prefs):
        (gpg_keycache_sync): Copy uid prefs so the key property
        dialog show the correct values. Thanks to Shane.
         


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26