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

Annotation of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 121 - (hide annotations)
Mon Dec 12 11:19:56 2005 UTC (19 years, 2 months ago) by twoaday
File size: 15234 byte(s)
2005-12-11  Timo Schulz  <ts@g10code.com>
 
        * wptW32API.cpp (get_file_version): New.
        * wptGPGUtil.cpp (create_process): Always hide window.
        * wptClipEditDlg.cpp (clipedit_dlg_proc): Use 'Close'
        instead of 'Exit'.
        * wptKeyManager.cpp (km_http_import): New filename
        generation code.
        (km_send_to_mail_recipient): Cleanups.
        * wptKeyEditDlg.cpp (showpref_dlg_proc): Localize dialog.
        * wptKeyManagerDlg.cpp (update_ui_items): Handle the case
        when multiple keys are selected.
        (popup_multiple): New.
        * WinPT.cpp (WinMain): Check that the PTD.dll and WinPT.exe
        file versions are equal. Rewrote --keymanager code.
         
Removed temporary w32gpgme dirctory, all code is now in Src.
Changed configure files.


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     safe_free(pkt);
124     return 0;
125     }
126     }
127     inp = gpg_iobuf_open (pubring);
128     if (!inp) {
129     safe_free( pkt );
130     return gpg_error (GPG_ERR_KEYRING_OPEN);
131     }
132     gpg_iobuf_ioctl( inp, 3, 1, NULL ); /* disable cache */
133    
134     gpg_init_packet( pkt );
135     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     gpgme_error_t
521     gpg_keycache_sync (gpg_keycache_t pub, gpg_keycache_t sec)
522     {
523     struct keycache_s *c, *c_sec;
524     gpgme_key_t key;
525    
526     if (!pub || !sec)
527     return gpg_error (GPG_ERR_INV_ARG);
528    
529     for (c=sec->item; c; c=c->next) {
530     if (!gpg_keycache_find_key2 (pub, c->key->subkeys->keyid, 0, &key, &c_sec)) {
531     c_sec->gloflags.is_protected = c->gloflags.is_protected;
532     c_sec->gloflags.divert_to_card = c->gloflags.divert_to_card;
533     if (!c->gloflags.divert_to_card)
534     c->gloflags.divert_to_card = key_divert_to_card (key);
535     c->pubpart = c_sec;
536     c->pubpart->key = key;
537     }
538     }
539     return 0;
540     }
541    
542    
543     /* Rewind the given cache @ctx to the begin. */
544     void
545     gpg_keycache_rewind (gpg_keycache_t ctx)
546     {
547     if (ctx)
548     ctx->pos = 0;
549     }
550    
551    
552    
553     /* Return the number of elements in the cache @ctx. */
554     int
555     gpg_keycache_get_size (gpg_keycache_t ctx)
556     {
557     struct keycache_s *c;
558     int count = 0;
559    
560     if (!ctx)
561     return 0;
562     for (c = ctx->item; c; c = c->next)
563     count++;
564     return count;
565     }
566    
567    
568     static gpgme_error_t
569     keycache_next_key (gpg_keycache_t ctx, int flags,
570     struct keycache_s **c, gpgme_key_t *r_key)
571     {
572     if (!ctx || !r_key)
573     return gpg_error (GPG_ERR_INV_ARG);
574    
575     if (!ctx->pos)
576     ctx->tmp = ctx->item;
577    
578     if (!ctx->tmp || !ctx->tmp->key) {
579     ctx->pos = 0;
580     *r_key = NULL;
581     return gpg_error (GPG_ERR_EOF);
582     }
583    
584     *r_key = flags? ctx->tmp->pubpart->key : ctx->tmp->key;
585     *c = ctx->tmp = ctx->tmp->next;
586     ctx->pos++;
587    
588     return 0;
589     }
590    
591    
592     /* Return the next key from the cache @ctx. The key will be returned
593     in @r_key. @flags can contain additional flags.
594     Return value: 0 on success. */
595     gpgme_error_t
596     gpg_keycache_next_key (gpg_keycache_t ctx, int flags, gpgme_key_t *r_key)
597     {
598     struct keycache_s *c=NULL;
599     gpgme_error_t err = 0;
600    
601     err = keycache_next_key (ctx, flags, &c, r_key);
602     return err;
603     }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26