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

Annotation of /trunk/Src/wptCardEdit.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26