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

Annotation of /trunk/Src/wptCardEdit.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 270 - (hide annotations)
Sat Oct 21 18:08:57 2006 UTC (18 years, 4 months ago) by twoaday
File size: 15618 byte(s)


1 werner 36 /* wptCardEdit.cpp - OpenPGP editing interface
2 twoaday 200 * Copyright (C) 2005, 2006 Timo Schulz
3 werner 36 *
4     * This file is part of WinPT.
5     *
6     * WinPT 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     * WinPT 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 WinPT; if not, write to the Free Software Foundation,
18     * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19     */
20    
21     #ifdef HAVE_CONFIG_H
22     #include <config.h>
23     #endif
24    
25     #include <windows.h>
26     #include <time.h>
27    
28 twoaday 260 #include "wptGPG.h"
29 werner 36 #include "wptCard.h"
30     #include "wptCardEdit.h"
31     #include "wptErrors.h"
32 twoaday 260 #include "wptTypes.h"
33     #include "wptW32API.h"
34 werner 36
35     /* Create a new Smartcard context. */
36     static gpgme_error_t
37     gpg_card_new (gpg_card_t *ret_card)
38     {
39     gpg_card_t c;
40    
41     if (!ret_card)
42     return gpg_error (GPG_ERR_INV_ARG);
43     *ret_card = NULL;
44     c = (gpg_card_t)calloc (1, sizeof *c);
45     if (!c)
46     return gpg_error (GPG_ERR_ENOMEM);
47     *ret_card = c;
48     return 0;
49     }
50    
51    
52     /* Release an existing Smartcard context. @card. */
53     void
54     gpg_card_release (gpg_card_t card)
55     {
56     int i;
57    
58     if (!card)
59     return;
60 twoaday 260 safe_free (card->aid);
61     safe_free (card->version);
62     safe_free (card->lang);
63     safe_free (card->login);
64     for (i=0; i < N_CARD_FPR; i++) {
65     safe_free (card->fpr[i]);
66     safe_free (card->ca_fpr[i]);
67     safe_free (card->fpr_created_str[i]);
68 werner 36 }
69 twoaday 260 safe_free (card->surname);
70     safe_free (card->givenname);
71     safe_free (card->serial);
72     safe_free (card->vendor);
73     safe_free (card->url);
74     safe_free (card->card_type);
75     safe_free (card);
76 werner 36
77     }
78    
79    
80     /* Parse the timestamp @long_ts and return a string
81 twoaday 260 representation of it (format: depens on locale setting). */
82 werner 36 static char*
83     get_str_timestamp (long long_ts)
84     {
85 twoaday 260 char timebuf[64];
86     const char *dat;
87 werner 36
88 twoaday 260 if (long_ts < 1)
89     return strdup ("");
90     dat = get_locale_date (long_ts, timebuf, sizeof (timebuf)-1);
91     if (!dat)
92     return strdup ("");
93    
94     return strdup (dat);
95 werner 36 }
96    
97    
98 twoaday 260 /* Parse the card version AABB => 0100 */
99     static void
100     parse_version (gpg_card_t card, const char *ver)
101     {
102     char buf[6];
103    
104     if (strlen (ver) != 4)
105     return;
106     buf[0] = *ver++;
107     buf[1] = *ver++;
108     buf[2] = 0;
109     buf[3] = *ver++;
110     buf[4] = *ver++;
111     buf[5] = 0;
112     card->ver[0] = atoi (buf);
113     card->ver[1] = atoi (buf+3);
114     }
115    
116    
117 werner 36 /* Colon handler for parsing the GPG card colon output. */
118     static gpgme_error_t
119     statuscard_colon_handler (gpg_card_t card, char * line)
120     {
121     enum rectype_t {
122     CARD_None = 0,
123     CARD_AID,
124     CARD_Version,
125     CARD_Vendor,
126     CARD_Serial,
127     CARD_Name,
128     CARD_Lang,
129     CARD_Sex,
130     CARD_Url,
131     CARD_Login,
132     CARD_MaxPinLen,
133     CARD_SigCount,
134     CARD_CAFpr,
135     CARD_Fpr,
136     CARD_FprTime
137     };
138 twoaday 270 enum rectype_t rectype = CARD_None;
139 werner 36 char *p, *pend;
140     int field = 0;
141    
142     if (!line)
143     return gpg_error (GPG_ERR_EOF);
144    
145     for (p = line; p; p = pend) {
146     field++;
147     pend = strchr (p, ':');
148     if (pend)
149     *pend++ = 0;
150    
151     if (field == 1) {
152     if (!strcmp (p, "AID"))
153     rectype = CARD_AID;
154     else if( !strcmp( p, "version" ) )
155     rectype = CARD_Version;
156     else if( !strcmp( p, "vendor" ) )
157     rectype = CARD_Vendor;
158     else if( !strcmp( p, "serial" ) )
159     rectype = CARD_Serial;
160     else if( !strcmp( p, "name" ) )
161     rectype = CARD_Name;
162     else if( !strcmp( p, "lang" ) )
163     rectype = CARD_Lang;
164     else if( !strcmp( p, "sex" ) )
165     rectype = CARD_Sex;
166     else if( !strcmp( p, "url" ) )
167     rectype = CARD_Url;
168     else if( !strcmp( p, "login" ) )
169     rectype = CARD_Login;
170     else if( !strcmp( p, "maxpinlen" ) )
171     rectype = CARD_MaxPinLen;
172     else if( !strcmp( p, "sigcount" ) )
173     rectype = CARD_SigCount;
174     else if (!strcmp (p, "cafpr"))
175     rectype = CARD_CAFpr;
176     else if (!strcmp (p, "fpr"))
177     rectype = CARD_Fpr;
178     else if (!strcmp (p, "fprtime"))
179     rectype = CARD_FprTime;
180     else
181     rectype = CARD_None;
182     }
183     switch (rectype) {
184     case CARD_AID:
185     if (field == 2) {
186     card->aid = strdup (p);
187     if (!card->aid)
188     return gpg_error (GPG_ERR_ENOMEM);
189     }
190     else if (field == 3) {
191     card->card_type = strdup (p);
192     if (!card->card_type)
193     return gpg_error (GPG_ERR_ENOMEM);
194     }
195     break;
196    
197     case CARD_Version:
198     if (field == 2) {
199     card->version = strdup (p);
200     if (!card->version)
201     return gpg_error (GPG_ERR_ENOMEM);
202 twoaday 260 parse_version (card, p);
203 werner 36 }
204     break;
205    
206     case CARD_Vendor:
207     if (field == 3) {
208     card->vendor = strdup (p);
209     if (!card->vendor)
210     return gpg_error (GPG_ERR_ENOMEM);
211     }
212     break;
213    
214     case CARD_Serial:
215     if (field == 2) {
216     card->serial = strdup (p);
217     if (!card->serial)
218     return gpg_error (GPG_ERR_ENOMEM);
219     }
220     break;
221     case CARD_Name:
222     if (field == 2) {
223     card->givenname = strdup (p);
224     if (!card->givenname)
225     return gpg_error (GPG_ERR_ENOMEM);
226     }
227     else if (field == 3) {
228     card->surname = strdup (p);
229     if (!card->surname)
230     return gpg_error (GPG_ERR_ENOMEM);
231     }
232     break;
233     case CARD_Lang:
234     if( field == 2 ) {
235     card->lang = strdup (p);
236     if (!card->lang)
237     return gpg_error (GPG_ERR_ENOMEM);
238     }
239     break;
240     case CARD_Sex:
241     if( field == 2 )
242     card->sex = *p;
243     break;
244    
245     case CARD_Url:
246     if( field == 2 ) {
247     if (card->url)
248     free (card->url);
249     card->url = (char*)calloc (1, strlen (p) + 1);
250     if( !card->url ) {
251     return gpg_error (GPG_ERR_ENOMEM);
252     }
253     gpg_decode_c_string (p, &card->url, strlen (p) + 1);
254     if (!card->url)
255     return gpg_error (GPG_ERR_ENOMEM);
256     }
257     break;
258    
259     case CARD_Login:
260     if (field == 2) {
261     card->login = strdup (p);
262     if (!card->login)
263     return gpg_error (GPG_ERR_ENOMEM);
264     }
265     break;
266    
267     case CARD_MaxPinLen:
268     break;
269    
270     case CARD_SigCount:
271     if (field == 2)
272     card->sig_count = atol (p);
273     break;
274    
275     case CARD_CAFpr:
276     if (!p)
277     break;
278     if (field > 4 || field == 1)
279     break;
280     card->ca_fpr[field-2] = strdup (p);
281     if (!card->ca_fpr[field-2])
282     return gpg_error (GPG_ERR_ENOMEM);
283     break;
284    
285     case CARD_Fpr:
286 twoaday 260 if (field > 4 || field == 1) /* max N_CARD_FPR=3 fprs */
287 werner 36 break;
288     card->fpr[field-2] = strdup (p);
289     if (!card->fpr[field-2])
290     return gpg_error (GPG_ERR_ENOMEM);
291     break;
292    
293     case CARD_FprTime:
294     if (field > 4 || field == 1)
295     break;
296     card->fpr_created[field-2] = strtoul (p, NULL, 10);
297 twoaday 260 if (card->fpr_created[field-2] > 0)
298     card->fpr_created_str[field-2] = get_str_timestamp (strtoul (p, NULL, 10));
299     else
300     card->fpr_created_str[field-2] = NULL;
301 werner 36 break;
302 twoaday 260
303 twoaday 69 default:
304     break;
305 twoaday 260
306 werner 36 }
307     }
308     return 0;
309     }
310    
311    
312     /* Dummy handler to get the colon data and then quit. */
313     static gpgme_error_t
314     list_handler (void *opaque, gpgme_status_code_t code, const char *key, int fd)
315     {
316     static int wait_card=0;
317     GpgCardEdit *ce = (GpgCardEdit *)opaque;
318 twoaday 270 const char *s = "";
319 werner 36 DWORD n;
320    
321 twoaday 270 if (!ce)
322     return gpg_error (GPG_ERR_INV_VALUE);
323    
324 werner 36 if (code == GPGME_STATUS_CARDCTRL) {
325     if (!strcmp (key, "5"))
326     ce->setResult (GPG_CARDRES_NOCARD);
327     else if (!strcmp (key, "1"))
328     wait_card = 1;
329     }
330     if (wait_card && !strcmp (key, "cardctrl.insert_card.okay")) {
331 twoaday 270 /* :TODO: show card ID */
332 werner 36 n = MessageBox (NULL, _("Please insert the card and click OK or Cancel to abort."),
333     _("GPG Card Status"), MB_ICONQUESTION|MB_OKCANCEL);
334     if (n == IDCANCEL) {
335 twoaday 270 s = "c\n";
336 werner 36 ce->setResult (GPG_CARDRES_CANCEL);
337 twoaday 270 WriteFile ((HANDLE)fd, s, strlen (s), &n, NULL);
338 werner 36 wait_card = 0;
339     }
340     }
341     if (!strcmp (key, "cardedit.prompt")) {
342     s = "quit\n";
343     if (!WriteFile ((HANDLE)fd, s, strlen (s), &n, NULL))
344     log_debug ("list_handler: WriteFile() failed ec=%d\r\n",
345     (int)GetLastError ());
346     wait_card = 0;
347     }
348     return 0;
349     }
350    
351    
352     /* Construct an empty object. */
353     GpgCardEdit::GpgCardEdit (void)
354     {
355     pin = NULL;
356     pin_new = NULL;
357     admin_pin = NULL;
358    
359     keygen.comment = NULL;
360     keygen.email = NULL;
361     keygen.name = NULL;
362     keygen.expdate = NULL;
363     keygen.key_fpr = NULL;
364    
365     type = 0;
366     cnt = 0;
367     cancel = 0;
368     result = 0;
369    
370     gpgme_new (&ctx); /* XXX: check return code */
371     }
372    
373     /* Release the object. */
374     GpgCardEdit::~GpgCardEdit (void)
375     {
376     if (keygen.name)
377     free (keygen.name);
378     if (keygen.comment)
379     free (keygen.comment);
380     if (keygen.email)
381     free (keygen.email);
382     if (keygen.expdate)
383     free (keygen.expdate);
384     if (keygen.key_fpr)
385     free (keygen.key_fpr);
386     gpgme_release (ctx);
387     }
388    
389    
390     /* Set the user PIN for the object to @pin. */
391     void
392 twoaday 69 GpgCardEdit::setPIN (const char *_pin)
393 werner 36 {
394 twoaday 69 this->pin = _pin;
395 werner 36 }
396    
397 twoaday 270
398 werner 36 /* Set the admin PIN for the object to @admin_pin. */
399     void
400 twoaday 69 GpgCardEdit::setAdminPIN (const char *_admin_pin)
401 werner 36 {
402 twoaday 69 this->admin_pin = _admin_pin;
403 werner 36 }
404    
405    
406     /* Set the new user PIN for the object to @new_pin. */
407     void
408 twoaday 69 GpgCardEdit::setNewPIN (const char *_new_pin)
409 werner 36 {
410 twoaday 69 this->pin_new = _new_pin;
411 werner 36 }
412    
413    
414     /* Set the passphrase needed when generating a key to @pass. */
415     void
416 twoaday 69 GpgCardEdit::setKeygenPassphrase (const char *_pass)
417 werner 36 {
418 twoaday 69 this->keygen.pass = _pass;
419 werner 36 }
420    
421    
422     /* Set the callback to @cb and the hook value to @cb_value. */
423     void
424 twoaday 260 GpgCardEdit::setCallback (const char* (*_cb)(int code, void *opaque),
425 twoaday 77 void *_cb_value)
426 werner 36 {
427 twoaday 77 this->cb_value = _cb_value;
428     this->card_cb = _cb;
429 werner 36 }
430    
431    
432     /* Read the information from the inserted card and return
433     it in form of a card context @r_card.
434     Return value: 0 on success. */
435     gpgme_error_t
436     GpgCardEdit::getCardStatus (gpg_card_t *r_card)
437     {
438     gpgme_data_t out = NULL;
439     gpgme_error_t err;
440 twoaday 270 gpg_card_t card = NULL;
441 werner 36 char buf[200];
442    
443     if (!r_card)
444     return gpg_error (GPG_ERR_INV_ARG);
445 twoaday 270 *r_card = NULL;
446 werner 36
447     err = gpg_card_new (&card);
448     if (err)
449     return err;
450    
451     err = gpgme_data_new (&out);
452     if (err) {
453     gpg_card_release (card);
454     return err;
455     }
456    
457     err = gpgme_op_card_edit (ctx, NULL, list_handler, this, out);
458     gpgme_data_rewind (out);
459     if (err) {
460     gpgme_data_release (out);
461     gpg_card_release (card);
462     return err;
463     }
464     if (getResult () & GPG_CARDRES_NOCARD ||
465     getResult () & GPG_CARDRES_CANCEL) {
466     gpg_card_release (card);
467     gpgme_data_release (out);
468     return gpg_error (GPG_ERR_CARD_NOT_PRESENT);
469     }
470    
471     *r_card = card;
472     while (gpg_data_readline (out, buf, sizeof (buf)-2) > 0) {
473     err = statuscard_colon_handler (card, buf);
474     if (err)
475     break;
476     }
477     gpgme_data_release (out);
478    
479     return err;
480     }
481    
482    
483     /* Generate a key on a smart card with the following params:
484     @flags: user specific params.
485     @name: name of the key holder.
486     @email: email of the key holder.
487     @comment: optional comment.
488     @valid: how long is the key valid in days.
489     Return value: 0 on success. */
490     gpgme_error_t
491 twoaday 270 GpgCardEdit::genKey (int flags,
492     const char *name, const char *email, const char *comment,
493     long valid, char **r_key_fpr)
494 werner 36 {
495     gpgme_error_t err;
496    
497     if (!name || !email)
498     return gpg_error (GPG_ERR_INV_ARG);
499     if (!this->keygen.pass)
500     return gpg_error (GPG_ERR_INV_OBJ);
501    
502     type = GPG_EDITCARD_GENKEY;
503     this->keygen.flags = flags;
504    
505     if (this->keygen.name)
506     free (this->keygen.name);
507     this->keygen.name = strdup (name);
508     if (this->keygen.email)
509     free (this->keygen.email);
510     this->keygen.email = strdup (email);
511     if (this->keygen.comment)
512     free (this->keygen.comment);
513     this->keygen.comment = comment? strdup (comment) : strdup ("");
514     if (this->keygen.expdate)
515     free (this->keygen.expdate);
516     this->keygen.expdate = (char*)calloc (1, 16);
517     if (this->keygen.expdate)
518 twoaday 77 sprintf (this->keygen.expdate, "%lu", valid);
519 werner 36
520     if (!this->keygen.name || !this->keygen.email)
521     return gpg_error (GPG_ERR_ENOMEM);
522    
523     err = gpg_card_edit (ctx, this);
524     if (!err)
525     err = getResult () & GPG_CARDRES_CANCEL? gpg_error (GPG_ERR_CANCELED) : 0;
526     if (!err && r_key_fpr)
527     *r_key_fpr = strdup (keygen.key_fpr? keygen.key_fpr : "");
528     return err;
529     }
530    
531    
532     /* Change the pin from @pin to @pin_new.
533     Return value: 0 on success. */
534     gpgme_error_t
535 twoaday 69 GpgCardEdit::changePIN (int _type)
536 werner 36 {
537     gpgme_error_t err;
538    
539     if (!this->pin_new)
540     return gpg_error (GPG_ERR_INV_ARG);
541    
542 twoaday 69 if (!_type) {
543 werner 36 if (this->pin && this->pin_new)
544     this->type = GPG_EDITCARD_CHUPIN;
545     else if (this->pin && this->admin_pin)
546     this->type = GPG_EDITCARD_CHAPIN;
547     else
548     this->type = GPG_EDITCARD_UNBPIN;
549     }
550     else
551 twoaday 69 this->type = _type;
552 werner 36 /* check if the user provided the needed PIN. */
553     if ((this->type == GPG_EDITCARD_CHUPIN && !this->pin) ||
554     (this->type == GPG_EDITCARD_CHAPIN && !this->admin_pin))
555     return gpg_error (GPG_ERR_INV_ARG);
556    
557     err = gpg_card_edit (ctx, this);
558     return err;
559     }
560    
561    
562 twoaday 270 /* Update the given and the surname on the card. */
563 werner 36 gpgme_error_t
564     GpgCardEdit::updateName (const char *given, const char *sur)
565     {
566     gpgme_error_t err;
567    
568     if (!this->admin_pin)
569     return gpg_error (GPG_ERR_INV_OBJ);
570    
571     this->type = GPG_EDITCARD_NAME;
572     this->edit.surname = sur;
573     this->edit.givenname = given;
574    
575     err = gpg_card_edit (ctx, this);
576     return err;
577     }
578 twoaday 270
579     /* Update the given URL on the card. */
580 werner 36 gpgme_error_t
581 twoaday 69 GpgCardEdit::updateURL (const char *_url)
582 werner 36 {
583     gpgme_error_t err;
584    
585     if (!this->admin_pin)
586     return gpg_error (GPG_ERR_INV_OBJ);
587    
588     type = GPG_EDITCARD_KEYURL;
589 twoaday 69 this->edit.keyurl = _url;
590 werner 36
591     err = gpg_card_edit (ctx, this);
592     return err;
593     }
594    
595    
596     gpgme_error_t
597     GpgCardEdit::updateLogin (const char *login)
598     {
599     gpgme_error_t err;
600    
601     if (!this->admin_pin)
602     return gpg_error (GPG_ERR_INV_OBJ);
603    
604     this->type = GPG_EDITCARD_LOGIN;
605     this->edit.login = login;
606    
607     err = gpg_card_edit (ctx, this);
608     return err;
609     }
610    
611 twoaday 270
612 werner 36 gpgme_error_t
613     GpgCardEdit::updateSex (char sex)
614     {
615     gpgme_error_t err;
616    
617     if (!this->admin_pin)
618     return gpg_error (GPG_ERR_INV_OBJ);
619    
620     type = GPG_EDITCARD_SEX;
621     this->edit.sex = sex;
622    
623     err = gpg_card_edit (ctx, this);
624     return err;
625     }
626    
627     gpgme_error_t
628     GpgCardEdit::updateLanguage (const char *lang)
629     {
630     gpgme_error_t err;
631    
632     if (!this->admin_pin)
633     return gpg_error (GPG_ERR_INV_OBJ);
634    
635     type = GPG_EDITCARD_LANG;
636     this->edit.lang = lang;
637    
638     err = gpg_card_edit (ctx, this);
639     return err;
640     }
641    
642    
643     /* Fetch the key specified by the url stored on the card.
644     Return value: 0 on success. */
645     gpgme_error_t
646     GpgCardEdit::fetchKey (void)
647     {
648 twoaday 260 gpgme_error_t err = 0;
649    
650 werner 36 if (!this->pin)
651     return gpg_error (GPG_ERR_INV_OBJ);
652    
653 twoaday 260 return err;
654 werner 36 }
655    
656    
657     /* Dispatcher for the various commands. @cmd is the card command ID
658     and @arg1 and @arg2 the actual values for the command.
659     Return value: 0 on success. */
660     gpgme_error_t
661     GpgCardEdit:: doCmd (int cmd, const char *arg1, const char *arg2)
662     {
663     switch (cmd) {
664     case GPG_EDITCARD_NAME:
665     return updateName (arg1, arg2); /* given, surname */
666    
667     case GPG_EDITCARD_LANG:
668     return updateLanguage (arg1); /* lang */
669    
670     case GPG_EDITCARD_SEX:
671     return updateSex (*arg1); /* sex */
672    
673     case GPG_EDITCARD_KEYURL:
674     return updateURL (arg1); /* url */
675    
676     case GPG_EDITCARD_LOGIN:
677     return updateLogin (arg1); /* login */
678    
679     default:
680     return gpg_error (GPG_ERR_INV_VALUE);
681     }
682    
683     return 0;
684     }
685    
686    
687     /* Set the result for the executed operation.
688     The values will be ORed. */
689     void
690     GpgCardEdit::setResult (int res)
691     {
692     result |= res;
693     }
694    
695    
696     /* Return the result of the executed operation. */
697     int
698     GpgCardEdit::getResult (void)
699     {
700     return result;
701     }
702    
703    
704     /* Reset the object state. */
705     void
706     GpgCardEdit::reset (void)
707     {
708     cnt = 0;
709     }
710    
711    
712     /* Return card command type */
713     int
714     GpgCardEdit::getType (void)
715     {
716     return type;
717     }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26