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

Annotation of /trunk/Src/wptKeyCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 181 - (hide annotations)
Tue Mar 14 11:01:22 2006 UTC (18 years, 11 months ago) by twoaday
File size: 22249 byte(s)
2006-03-12  Timo Schulz  <ts@g10code.de>
 
        * wptGPG.cpp (gnupg_load_config): Search for 'ask-cert-expire'.
        * wptKeyPropsDlg.cpp (display_key_info): Automatically update
        sym algorithm preferences if needed.
        * wptKeysignDlg.cpp (date_is_today): New.
        (keysign_dlg_proc): Only allow to set cert expire date if
        the option was found.
        * wptGPGPrefsDlg.cpp (gpgprefs_dlg_proc): Allow to set
        'ask-cert-expire'.
         


1 werner 36 /* wptKeyCache.cpp- Caching for the pub- and the secring
2 twoaday 133 * Copyright (C) 2001-2006 Timo Schulz
3 werner 36 *
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 twoaday 133 #include "wptGPG.h"
39 twoaday 181 #include "wptTypes.h"
40 werner 36
41    
42 twoaday 133 /* Attribute list which holds the image data. */
43     struct attr_list_s {
44     struct attr_list_s *next;
45     char *fpr; /* fingerprint of the key */
46     unsigned char *d; /* actual JPEG data. */
47     unsigned long octets; /* length of the data. */
48     unsigned int flags; /* status of the attribute. */
49     };
50     typedef struct attr_list_s *attr_list_t;
51    
52    
53 twoaday 181 /* Free attribute list @ctx. */
54 twoaday 133 void
55     free_attr_list (attr_list_t ctx)
56 werner 36 {
57 twoaday 133 attr_list_t n;
58     while (ctx) {
59     n = ctx->next;
60     free (ctx->fpr);
61     free (ctx->d);
62     ctx = n;
63     }
64     }
65    
66     /* Parse the attribute list in @fp and store it into @ctx.
67     Return value: number of parsed items. */
68     int
69     parse_attr_list (FILE *fp, const BYTE *data, DWORD datlen, attr_list_t *ctx)
70     {
71     attr_list_t c, t;
72     char buf[512], *p, *buffer;
73     int pos, n=0;
74    
75     *ctx = NULL;
76     while (fgets (buf, 511, fp)) {
77     if (strstr (buf, "\r\n"))
78     buf[strlen (buf)-2]=0;
79     if (strstr (buf, "\n"))
80     buf[strlen (buf)-1]=0;
81     if (strlen (buf) < 2 || !strstr (buf, "ATTRIBUTE"))
82     continue;
83     buffer = buf+9+10;
84     pos = 0;
85     c = (attr_list_t)calloc (1, sizeof *c);
86 twoaday 181 if (!c)
87     BUG (0);
88 twoaday 133 p = strtok (buffer, " ");
89     while (p != NULL) {
90     switch (pos) {
91     case 0:
92     c->fpr = strdup (p);
93     break;
94    
95     case 1:
96     c->octets = strtoul (p, NULL, 10);
97     break;
98    
99     case 7:
100     c->flags = strtoul (p, NULL, 10);
101     break;
102    
103     default:
104     break;
105     }
106     pos++;
107     p = strtok (NULL, " ");
108     }
109     if (!*ctx)
110     *ctx = c;
111     else {
112     for (t = *ctx; t->next; t=t->next)
113     ;
114     t->next = c;
115     }
116     c->d = (unsigned char*)malloc (c->octets);
117 twoaday 181 if (!c->d)
118     BUG (0);
119 twoaday 133 memcpy (c->d, data, c->octets);
120     data += c->octets;
121     datlen -= c->octets;
122     n++;
123     }
124     /*assert (datlen == 0); */
125     return n;
126     }
127 werner 36
128 twoaday 133
129     static int
130     parse_attr_data (const char *keyid, attr_list_t *list)
131     {
132     gpgme_error_t err;
133 twoaday 175 FILE *tmp;
134     BYTE *data;
135 twoaday 164 char *status, tmpnam[MAX_PATH+1];
136 twoaday 175 DWORD ndata = 0;
137 twoaday 133
138     err = gpg_get_photoid_data (keyid, &status, &data, &ndata);
139     if (err)
140     return err;
141    
142 twoaday 175 get_temp_name (tmpnam, MAX_PATH, NULL);
143     tmp = fopen (tmpnam, "w+b");
144     if (ndata > 0 && tmp != NULL) {
145 twoaday 133 fwrite (status, 1, strlen (status), tmp);
146     fflush (tmp);
147     rewind (tmp);
148    
149     ndata = parse_attr_list (tmp, data, ndata, list);
150     fclose (tmp);
151 twoaday 164 DeleteFile (tmpnam);
152 werner 36 }
153 twoaday 133 else
154     *list = NULL;
155    
156     safe_free (status);
157     safe_free (data);
158     return ndata;
159 werner 36 }
160    
161 twoaday 121
162 werner 36 /* Parse the secret keyring and retrieve some additional information
163     for each key which was found. */
164     static void
165     parse_secring (gpg_keycache_t cache, const char *kid, const char *secring)
166     {
167 twoaday 133 PACKET *pkt;
168 werner 36 PKT_secret_key *sk;
169     gpg_iobuf_t inp;
170     gpgme_error_t err;
171     gpgme_key_t key;
172     struct keycache_s *c=NULL;
173     char keyid[16+1];
174    
175     inp = gpg_iobuf_open (secring);
176 twoaday 133 if (!inp)
177 werner 36 return;
178 twoaday 133
179 werner 36 gpg_iobuf_ioctl (inp, 3, 1, NULL);
180 twoaday 133 pkt = (PACKET*)calloc (1, sizeof *pkt);
181 twoaday 181 if (!pkt)
182     BUG (0);
183 werner 36 gpg_init_packet (pkt);
184     while (gpg_parse_packet (inp, pkt) != -1) {
185     if (pkt->pkttype == PKT_SECRET_KEY) {
186     sk = pkt->pkt.secret_key;
187     /* XXX: key IDs of card public keys are wrong! */
188     _snprintf (keyid, sizeof (keyid)-1, "%08lX",
189     gpg_keyid_from_sk (sk, NULL));
190     if (kid && strcmp (kid, keyid) != 0)
191     goto next;
192     err = gpg_keycache_find_key2 (cache, keyid, 0, &key, &c);
193     if (err)
194     goto next;
195     c->gloflags.is_protected = sk->is_protected;
196     c->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;
197     if (c->pubpart != NULL) {
198     c->pubpart->gloflags.is_protected = sk->is_protected;
199     c->pubpart->gloflags.divert_to_card = sk->protect.s2k.mode==1002? 1 : 0;
200     }
201     }
202     next:
203     gpg_free_packet (pkt);
204     gpg_init_packet (pkt);
205     }
206     safe_free (pkt);
207     gpg_iobuf_close (inp);
208     }
209    
210    
211 twoaday 133 /* Update the photo image of a single key with the fingerprint
212     @fpr. The @dat struct contains the new item data. */
213     static gpgme_error_t
214     keycache_update_photo (gpg_keycache_t ctx, const char *fpr, attr_list_t dat)
215     {
216     struct keycache_s *fnd = NULL;
217     gpgme_key_t key;
218    
219     gpg_keycache_find_key2 (ctx, fpr, 0, &key, &fnd);
220     if (!fnd)
221     return gpg_error (GPG_ERR_NOT_FOUND);
222     safe_free (fnd->attrib.d);
223     fnd->attrib.flags = dat->flags;
224     fnd->attrib.len = dat->octets;
225     fnd->attrib.d = (unsigned char*)malloc (dat->octets);
226 twoaday 181 if (!fnd->attrib.d)
227     BUG (0);
228 twoaday 133 memcpy (fnd->attrib.d, dat->d, dat->octets);
229     return 0;
230     }
231    
232    
233     /* Update all photo images in the cache. */
234     static gpgme_error_t
235     keycache_update_photos (gpg_keycache_t ctx)
236     {
237     attr_list_t list=NULL, n;
238     DWORD ndata;
239    
240     ndata = parse_attr_data (NULL, &list);
241     if (ndata < 1) {
242     free_attr_list (list);
243     return 0;
244     }
245    
246     for (n=list; n; n=n->next)
247     keycache_update_photo (ctx, n->fpr, n);
248     free_attr_list (list);
249     return 0;
250     }
251    
252    
253 werner 36 /* Merge the information from the keyrings into the key cache structure. */
254     gpgme_error_t
255     keycache_prepare2 (gpg_keycache_t ctx, const char *kid,
256     const char *pubring, const char *secring)
257     {
258 twoaday 69 gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
259 werner 36 gpgme_key_t key = NULL;
260     gpg_iobuf_t inp;
261 twoaday 133 PACKET *pkt;
262 werner 36 struct keycache_s *c;
263     const byte *sym_prefs;
264 twoaday 133 char keyid[16+1];
265 werner 36 int key_seen = 0;
266 twoaday 65 size_t nsym =0;
267 werner 36
268     if (secring) {
269     parse_secring (ctx, kid, secring);
270 twoaday 133 if (!pubring)
271 werner 36 return 0;
272     }
273     inp = gpg_iobuf_open (pubring);
274 twoaday 133 if (!inp)
275 werner 36 return gpg_error (GPG_ERR_KEYRING_OPEN);
276 twoaday 123 gpg_iobuf_ioctl (inp, 3, 1, NULL); /* disable cache */
277 werner 36
278 twoaday 133 pkt = (PACKET*)calloc (1, sizeof * pkt);
279 twoaday 181 if (!pkt)
280     BUG (0);
281 twoaday 123 gpg_init_packet (pkt);
282 werner 36 while (gpg_parse_packet (inp, pkt) != -1) {
283     if (pkt->pkttype == PKT_PUBLIC_KEY) {
284     strcpy (keyid, "");
285     key_seen = 1;
286     }
287    
288 twoaday 133 if (pkt->pkttype == PKT_SIGNATURE &&
289     pkt->pkt.signature->sig_class == 0x1F) {
290 werner 36 if (pkt->pkt.signature->numrevkeys == 0)
291     goto next;
292 twoaday 133 _snprintf (keyid, sizeof (keyid) -1, "%08X",
293     pkt->pkt.signature->keyid[1]);
294 werner 36 if (kid && strcmp (kid, keyid) != 0)
295     goto next;
296     err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
297     if (err)
298     goto next;
299     c->gloflags.has_desig_rev = 1;
300     }
301     if (pkt->pkttype == PKT_SIGNATURE && key_seen == 1 ) {
302 twoaday 133 sym_prefs = gpg_parse_sig_subpkt (pkt->pkt.signature->hashed,
303     SIGSUBPKT_PREF_SYM, &nsym);
304     if (!sym_prefs)
305 werner 36 goto next;
306 twoaday 133 _snprintf (keyid, sizeof (keyid) - 1, "%08X",
307     pkt->pkt.signature->keyid[1]);
308 werner 36 if (kid && strcmp (kid, keyid) != 0)
309     goto next;
310     err = gpg_keycache_find_key2 (ctx, keyid, 0, &key, &c);
311     if (err)
312     goto next;
313     else if (nsym > 0) {
314     c->sym_prefs = (unsigned char*)calloc (1, nsym+1);
315     if (!c->sym_prefs)
316 twoaday 181 BUG (0);
317 werner 36 memcpy (c->sym_prefs, sym_prefs, nsym);
318     }
319     }
320     next:
321     gpg_free_packet (pkt);
322     gpg_init_packet(pkt);
323     }
324    
325     safe_free (pkt);
326     gpg_iobuf_close (inp);
327     return err;
328     }
329    
330    
331     gpgme_error_t
332     gpg_keycache_prepare (gpg_keycache_t ctx, const char *pubr, const char *secr)
333     {
334     return keycache_prepare2 (ctx, NULL, pubr, secr);
335     }
336    
337     gpgme_error_t
338     gpg_keycache_prepare_single (gpg_keycache_t ctx, const char *keyid,
339     const char *pubr, const char *secr)
340     {
341     if (!strncmp (keyid, "0x", 2))
342     keyid += 2;
343     return keycache_prepare2 (ctx, keyid, pubr, secr);
344     }
345    
346    
347     /* Create new keycache object and return it in @r_ctx.
348     Return value: 0 on success. */
349     gpgme_error_t
350     gpg_keycache_new (gpg_keycache_t *r_ctx)
351     {
352     gpg_keycache_t ctx;
353    
354     if (!r_ctx)
355     return gpg_error (GPG_ERR_INV_ARG);
356     ctx = (gpg_keycache_t)calloc (1, sizeof *ctx);
357     if (!ctx)
358 twoaday 181 BUG (0);
359 werner 36 ctx->secret = 0;
360     ctx->pos = 0;
361     *r_ctx = ctx;
362     return 0;
363     }
364    
365    
366     /* Release keycache object @ctx. */
367     void
368     gpg_keycache_release (gpg_keycache_t ctx)
369     {
370     struct keycache_s *c, *c2;
371    
372     if (!ctx)
373     return;
374    
375     for (c = ctx->item; c; c = c2) {
376     c2 = c->next;
377     gpgme_key_release (c->key);
378     c->key = NULL;
379 twoaday 181 safe_free (c->pref_keyserver);
380 twoaday 133 safe_free (c->sym_prefs);
381     safe_free (c->attrib.d);
382     safe_free (c->card_type);
383 werner 36 free (c);
384     }
385 twoaday 133 safe_free (ctx);
386 werner 36 }
387    
388    
389     /* Set (progress) callback for the given keycache object.
390     @ctx the keycache
391     @cb the callback function
392     @cb_value1 opaque value which is passed to the callback.
393     @cb_value2 see @cb_value1. */
394     void
395     gpg_keycache_set_cb (gpg_keycache_t ctx,
396     void (*cb)(void *, const char *, int, int, int),
397     void * cb_value1, int cb_value2)
398     {
399     if (!ctx)
400     return;
401     ctx->cb = cb;
402     ctx->cb_value = cb_value1;
403     ctx->cb_value2 = cb_value2;
404     }
405    
406    
407     /* Add @key to the cache @ctx. @opaque return the key cache context as a void*.
408     Return value: 0 on success. */
409     gpgme_error_t
410     gpg_keycache_add_key (gpg_keycache_t ctx, gpgme_key_t key, void **opaque)
411     {
412 twoaday 41 struct keycache_s *c, *n1;
413 werner 36
414     if (!ctx)
415     return gpg_error (GPG_ERR_INV_ARG);
416    
417     c = (struct keycache_s*)calloc (1, sizeof *c);
418     if (!c)
419 twoaday 181 BUG (0);
420 werner 36 c->gloflags.is_protected = 1; /*default: assume protection. */
421     c->key = key;
422     if (!ctx->item)
423     ctx->item = c;
424     else {
425     for (n1 = ctx->item; n1 && n1->next; n1 = n1->next)
426     ;
427     n1->next = c;
428     }
429     if (opaque)
430     *opaque = c;
431     return 0;
432     }
433    
434    
435    
436     #define has_keyid_len(pattern) (\
437     strlen (pattern) == 8 || strlen (pattern) == 10 || \
438     strlen (pattern) == 16 || strlen (pattern) == 18)
439    
440    
441     gpgme_error_t
442     gpg_keycache_find_key2 (gpg_keycache_t ctx, const char *pattern, int flags,
443     gpgme_key_t *r_key, struct keycache_s **r_item)
444     {
445     struct keycache_s *c;
446     gpgme_subkey_t s;
447     gpgme_user_id_t u;
448     gpgme_key_t key;
449     const char *kid;
450    
451     if (!ctx || !r_key)
452     return gpg_error (GPG_ERR_INV_ARG);
453    
454     if (strstr (pattern, "0x"))
455     pattern += 2;
456    
457     /* Sometimes a subkey has no valid fpr. As a kludge we convert v4
458     fingerprints into the 64-bit keyid. */
459     if (strlen (pattern) == 40 && isxdigit (*pattern))
460     pattern += 32;
461    
462     /* XXX: this code is very slow, revamp it and use hash tables whenever
463     it is possible. */
464     for (c = ctx->item; c; c = c->next) {
465     key = c->key;
466     assert (key->_refs >= 1);
467     for (s = key->subkeys; s; s = s->next) {
468     for (u = key->uids; u; u = u->next) {
469     if (u->name && stristr (u->name, pattern)) {
470     if (r_item)
471     *r_item = c;
472     *r_key = flags? c->pubpart->key : c->key;
473     return 0;
474     }
475     }
476     if (has_keyid_len (pattern))
477     kid = s->keyid;
478     else
479     kid = s->fpr;
480     if (kid && stristr (kid, pattern)) {
481     if (r_item)
482     *r_item = c;
483     *r_key = flags? c->pubpart->key : c->key;
484     return 0;
485     }
486     }
487     }
488     *r_key = NULL;
489     return gpg_error (GPG_ERR_INTERNAL);
490 twoaday 133 }
491 werner 36
492    
493     gpgme_error_t
494     gpg_keycache_find_key (gpg_keycache_t ctx, const char *pattern,
495     int flags, gpgme_key_t *r_key)
496     {
497     return gpg_keycache_find_key2 (ctx, pattern, flags, r_key, NULL);
498     }
499    
500    
501 twoaday 133 /* Reload a photo image of a single key with the keyid @keyid.
502     Return value: 0 on success. */
503     static gpgme_error_t
504     keycache_reload_photo (gpg_keycache_t ctx, const char *keyid)
505     {
506     attr_list_t list;
507    
508     if (parse_attr_data (keyid, &list) < 1) {
509     free_attr_list (list);
510     return 0;
511     }
512     keycache_update_photo (ctx, list->fpr, list);
513     free_attr_list (list);
514     return 0;
515     }
516    
517    
518 twoaday 147 /* Return the next key which was updated. Before it is
519     returned the update flag is cleared.
520 twoaday 150 @r_status is 1 for a new key and 2 for an updated key.
521 twoaday 147 Return value: 0 on success. */
522 werner 36 gpgme_error_t
523 twoaday 147 gpg_keycache_next_updated_key (gpg_keycache_t ctx,
524 twoaday 150 struct keycache_s **r_obj,
525     int *r_status)
526 twoaday 147 {
527     struct keycache_s *c;
528    
529     for (c = ctx->item; c; c = c->next) {
530 twoaday 150 if (c->flags != 0) {
531     *r_status = c->flags;
532 twoaday 147 c->flags = 0;
533     *r_obj = c;
534     return 0;
535     }
536     }
537     return gpg_error (GPG_ERR_NOT_FOUND);
538     }
539    
540    
541    
542     gpgme_error_t
543 werner 36 gpg_keycache_update_key (gpg_keycache_t ctx, int is_sec,
544     void *opaque, const char *keyid)
545     {
546     struct keycache_s *c = NULL, *c_new=NULL;
547     gpgme_key_t key=NULL, fndkey=NULL;
548     gpgme_error_t err;
549     gpgme_ctx_t gctx;
550     gpg_keycache_t pub = (gpg_keycache_t)opaque;
551    
552     err = gpgme_new (&gctx);
553     if (err)
554     return err;
555 twoaday 150 gpgme_set_keylist_mode (gctx, GPGME_KEYLIST_MODE_SIGS);
556 werner 36 err = gpgme_get_key (gctx, keyid, &key, is_sec);
557     gpgme_release (gctx);
558     if (err)
559     return err;
560     err = gpg_keycache_find_key2 (ctx, keyid, 0, &fndkey, &c);
561     if (!err && c != NULL) {
562     log_debug ("keycache update: keyid=%s %p\r\n", keyid, pub);
563     gpgme_key_release (fndkey);
564     c->key = key;
565 twoaday 150 c->flags = KC_FLAG_UPD;
566 werner 36 if (is_sec && pub != NULL &&
567     !gpg_keycache_find_key (pub, keyid, 0, &fndkey)) {
568     log_debug ("keycache update: set public part %p\r\n", fndkey);
569     c->pubpart->key = fndkey;
570     }
571 twoaday 133 /* XXX: this is also called for keys without a photo-id. */
572     keycache_reload_photo (ctx, keyid);
573 werner 36 }
574     else {
575     log_debug ("keycache add: sync public part\r\n");
576     if (is_sec)
577     gpg_keycache_find_key2 (pub, keyid, 0, &fndkey, &c_new);
578     gpg_keycache_add_key (ctx, key, (void **)&c);
579     if (c != NULL && is_sec) {
580     log_debug ("keycache add: keyid=%s %p %p\r\n", keyid, c, fndkey);
581     c->pubpart = c_new;
582     if (c_new != NULL) {
583     c->pubpart->key = fndkey;
584     c->gloflags.is_protected = c_new->gloflags.is_protected;
585     c->gloflags.divert_to_card = c_new->gloflags.divert_to_card;
586     }
587     }
588 twoaday 147 if (c)
589 twoaday 150 c->flags = KC_FLAG_ADD;
590 werner 36 }
591     return 0;
592     }
593    
594    
595     /* Delete a key from the cache @ctx with the pattern @pattern.
596     Return value: 0 on success. */
597     gpgme_error_t
598     gpg_keycache_delete_key (gpg_keycache_t ctx, const char *pattern)
599     {
600     struct keycache_s *itm = NULL, *c;
601     gpgme_key_t key;
602     gpgme_error_t rc;
603    
604     if (!ctx)
605     return gpg_error (GPG_ERR_INV_ARG);
606     rc = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);
607     if (rc)
608     return rc;
609    
610     c = ctx->item;
611     if (c->next == NULL) {
612     gpgme_key_release (itm->key);
613     if (itm)
614     free (itm);
615     ctx->item = NULL;
616     }
617     else {
618     while (c && c->next != itm)
619     c = c->next;
620     c->next = c->next->next;
621     gpgme_key_release (itm->key);
622     if (itm)
623     free (itm);
624     }
625     return 0;
626     }
627    
628    
629     /* Initialize the given cache @ctx. If @pattern is NULL, the entire keyring
630     will be added to the cache. @secret is 1 if the source is the secret keyring.
631     Return value: 0 on success. */
632     gpgme_error_t
633     gpg_keycache_init (gpg_keycache_t ctx, const char *pattern, int secret)
634     {
635     gpgme_error_t err;
636     gpgme_ctx_t c;
637     gpgme_key_t key;
638     int count = 0;
639    
640     if (!ctx)
641     return gpg_error (GPG_ERR_INV_ARG);
642    
643     err = gpgme_new (&c);
644     if (err)
645     return err;
646    
647     gpgme_set_keylist_mode (c, GPGME_KEYLIST_MODE_SIGS);
648     err = gpgme_op_keylist_start (c, pattern, secret);
649     while(!err) {
650     err = gpgme_op_keylist_next (c, &key);
651     if (!err)
652     err = gpg_keycache_add_key (ctx, key, NULL);
653     if (ctx->cb)
654     ctx->cb (ctx->cb_value, _("Load GPG Keyrings..."), 0,
655     count++, ctx->cb_value2);
656     }
657     if (gpgme_err_code (err) == GPG_ERR_EOF)
658     err = gpg_error (GPG_ERR_NO_ERROR);
659 twoaday 133 keycache_update_photos (ctx);
660 werner 36 /* XXX: make sure the progress dialog is closed. */
661     gpgme_op_keylist_end (c);
662     gpgme_release (c);
663     return err;
664     }
665    
666    
667     /* XXX: kludge to see if the key is stored on a card. */
668     static int
669     key_divert_to_card (gpgme_key_t key)
670     {
671     gpgme_subkey_t k;
672     int n=0, n_alg=0, can_auth = 0;
673    
674     for (k = key->subkeys; k; k = k->next) {
675     n++;
676     if (k->pubkey_algo == GPGME_PK_RSA && k->length == 1024)
677     n_alg++;
678     if (k->can_authenticate)
679     can_auth++;
680     }
681     if (n == 3 && n_alg == 3 && can_auth == 1)
682     return 1;
683     return 0;
684     }
685    
686    
687 twoaday 123 static unsigned char*
688     copy_uid_prefs (const unsigned char *prefs)
689     {
690     unsigned char *p;
691     size_t pos=0;
692    
693     while (prefs[pos] != 0)
694     pos++;
695     p = (unsigned char*)calloc (1, pos+1);
696     if (!p)
697 twoaday 181 BUG (0);
698 twoaday 123 memcpy (p, prefs, pos);
699     return p;
700     }
701    
702    
703 werner 36 gpgme_error_t
704     gpg_keycache_sync (gpg_keycache_t pub, gpg_keycache_t sec)
705     {
706     struct keycache_s *c, *c_sec;
707     gpgme_key_t key;
708    
709     if (!pub || !sec)
710     return gpg_error (GPG_ERR_INV_ARG);
711    
712     for (c=sec->item; c; c=c->next) {
713     if (!gpg_keycache_find_key2 (pub, c->key->subkeys->keyid, 0, &key, &c_sec)) {
714     c_sec->gloflags.is_protected = c->gloflags.is_protected;
715     c_sec->gloflags.divert_to_card = c->gloflags.divert_to_card;
716     if (!c->gloflags.divert_to_card)
717     c->gloflags.divert_to_card = key_divert_to_card (key);
718 twoaday 168 if (c_sec->sym_prefs)
719     c->sym_prefs = copy_uid_prefs (c_sec->sym_prefs);
720 werner 36 c->pubpart = c_sec;
721     c->pubpart->key = key;
722     }
723     }
724     return 0;
725     }
726    
727    
728     /* Rewind the given cache @ctx to the begin. */
729     void
730     gpg_keycache_rewind (gpg_keycache_t ctx)
731     {
732     if (ctx)
733     ctx->pos = 0;
734     }
735    
736    
737    
738     /* Return the number of elements in the cache @ctx. */
739     int
740     gpg_keycache_get_size (gpg_keycache_t ctx)
741     {
742     struct keycache_s *c;
743     int count = 0;
744    
745     if (!ctx)
746     return 0;
747     for (c = ctx->item; c; c = c->next)
748     count++;
749     return count;
750     }
751    
752    
753     static gpgme_error_t
754     keycache_next_key (gpg_keycache_t ctx, int flags,
755     struct keycache_s **c, gpgme_key_t *r_key)
756     {
757     if (!ctx || !r_key)
758     return gpg_error (GPG_ERR_INV_ARG);
759    
760     if (!ctx->pos)
761     ctx->tmp = ctx->item;
762    
763     if (!ctx->tmp || !ctx->tmp->key) {
764     ctx->pos = 0;
765     *r_key = NULL;
766     return gpg_error (GPG_ERR_EOF);
767     }
768 twoaday 150 if (ctx->tmp->flags != 0)
769     ctx->tmp->flags = 0; /* reset the 'updated' status. */
770 twoaday 165 /* it might be possible there is no public key. */
771     if (flags && ctx->tmp->pubpart == NULL)
772     flags = 0;
773 werner 36 *r_key = flags? ctx->tmp->pubpart->key : ctx->tmp->key;
774     *c = ctx->tmp = ctx->tmp->next;
775     ctx->pos++;
776    
777     return 0;
778     }
779    
780    
781     /* Return the next key from the cache @ctx. The key will be returned
782     in @r_key. @flags can contain additional flags.
783     Return value: 0 on success. */
784     gpgme_error_t
785     gpg_keycache_next_key (gpg_keycache_t ctx, int flags, gpgme_key_t *r_key)
786     {
787     struct keycache_s *c=NULL;
788     gpgme_error_t err = 0;
789    
790     err = keycache_next_key (ctx, flags, &c, r_key);
791     return err;
792     }
793 twoaday 167
794 twoaday 181
795 twoaday 167 /* Search for a key with the pattern @pattern and mark
796     this key as the default signing key if found.
797     Return value: 0 on success. */
798     gpgme_error_t
799     gpg_keycache_set_default_key (gpg_keycache_t ctx,
800     const char *pattern)
801     {
802     gpgme_error_t err;
803     gpgme_key_t key;
804     struct keycache_s *itm;
805    
806     err = gpg_keycache_find_key2 (ctx, pattern, 0, &key, &itm);
807     if (err)
808     return err;
809    
810     if (itm)
811     itm->default_key = 1;
812     return 0;
813     }
814    
815     /* Return the default key from the cache. If no was
816     marked before, NULL is returned in @r_key.
817     Return value: 0 on success. */
818     gpgme_error_t
819     gpg_keycache_get_default_key (gpg_keycache_t ctx,
820     gpgme_key_t *r_key)
821     {
822     struct keycache_s *itm;
823    
824     *r_key = NULL;
825     for (itm = ctx->item; itm; itm = itm->next) {
826     if (itm->default_key) {
827     *r_key = itm->key;
828     break;
829     }
830     }
831     if (!*r_key)
832     return gpgme_error (GPG_ERR_NOT_FOUND);
833     return 0;
834     }
835    
836    
837 twoaday 181 static gpgme_error_t
838     decode_subpacket (const char *subpkt_data, int *type,
839     char **out, WORD *outlen)
840     {
841     char tmp[128], *p = tmp, *val;
842     char *enc;
843     size_t pos = 0, i=0;
844 twoaday 167
845 twoaday 181 /* example: spk:24:1:21:http%3A//subkeys.pgp.de */
846     *outlen = 0;
847     *out = NULL;
848    
849     if (strncmp (subpkt_data, "spk:", 4))
850     return gpg_error (GPG_ERR_NO_DATA);
851    
852     strncpy (tmp, subpkt_data, 62);
853     val = strtok (tmp, ":");
854     while (val != NULL) {
855     switch (pos++) {
856     case 0:
857     break;
858    
859     case 1:
860     if (type)
861     *type = atoi (val);
862     break;
863    
864     case 2:
865     break;
866    
867     case 3:
868     *outlen = atoi (val);
869     break;
870    
871     case 4:
872     enc = strdup (val);
873     break;
874     }
875     val = strtok (NULL, ":");
876     }
877     if (!enc)
878     return gpg_error (GPG_ERR_NO_DATA);;
879     *out = (char*)calloc (1, strlen (enc)+1);
880     for (pos = 0; pos < strlen (enc); pos++) {
881     if (enc[pos] == '%' && enc[pos+1] == '%')
882     (*out)[i++] = '%';
883     else if (enc[pos] == '%') {
884     char tmp[3];
885     tmp[0] = enc[++pos];
886     tmp[1] = enc[++pos];
887     tmp[2] = 0;
888     (*out)[i++] = (char)strtoul (tmp, NULL, 16);
889     }
890     else
891     (*out)[i++] = enc[pos];
892     }
893     (*out)[i] = 0;
894     free (enc);
895     return 0;
896     }
897    
898    
899     /* If the attribute given in @attr is not set in the
900     key cache object, try to update it. */
901     gpgme_error_t
902     gpg_keycache_update_attr (struct keycache_s *item,
903     int attr, int force)
904     {
905     gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
906     char *val = NULL;
907     WORD n = 0;
908    
909     switch (attr) {
910     case KC_ATTR_PREFSYM:
911     if (!force && item->sym_prefs)
912     break;
913     safe_free (item->sym_prefs);
914     err = gpg_find_key_subpacket (item->key->subkeys->keyid+8, attr, &val);
915     if (!err && val != NULL)
916     err = decode_subpacket (val, NULL, (char**)&item->sym_prefs, &n);
917     break;
918    
919     case KC_ATTR_PREFKSERV:
920     if (!force && item->pref_keyserver)
921     break;
922     safe_free (item->pref_keyserver);
923     err = gpg_find_key_subpacket (item->key->subkeys->keyid+8, attr, &val);
924     if (!err && val != NULL)
925     err = decode_subpacket (val, NULL, &item->pref_keyserver, &n);
926     break;
927     }
928     safe_free (val);
929     return err;
930     }
931    

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26