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

Annotation of /trunk/Src/wptCardEdit.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 306 - (hide annotations)
Fri Mar 23 14:07:24 2007 UTC (17 years, 11 months ago) by twoaday
File size: 15508 byte(s)


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26