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

Contents of /trunk/Src/wptCardEdit.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 271 - (show annotations)
Sun Nov 5 08:57:45 2006 UTC (18 years, 3 months ago) by twoaday
File size: 15612 byte(s)


1 /* wptCardEdit.cpp - OpenPGP editing interface
2 * Copyright (C) 2005, 2006 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 <time.h>
27
28 #include "wptGPG.h"
29 #include "wptCard.h"
30 #include "wptCardEdit.h"
31 #include "wptErrors.h"
32 #include "wptTypes.h"
33 #include "wptW32API.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 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 }
69 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
77 }
78
79
80 /* Parse the timestamp @long_ts and return a string
81 representation of it (format: depens on locale setting). */
82 static char*
83 get_str_timestamp (long long_ts)
84 {
85 char timebuf[64];
86 const char *dat;
87
88 if (long_ts < 1)
89 return strdup ("");
90 dat = get_locale_date (long_ts, timebuf, DIM (timebuf)-1);
91 if (!dat)
92 return strdup ("");
93
94 return strdup (dat);
95 }
96
97
98 /* 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 /* 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 enum rectype_t rectype = CARD_None;
139 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 parse_version (card, p);
203 }
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 if (field > 4 || field == 1) /* max N_CARD_FPR=3 fprs */
287 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 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 break;
302
303 default:
304 break;
305
306 }
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 const char *s = "";
319 DWORD n;
320
321 if (!ce)
322 return gpg_error (GPG_ERR_INV_VALUE);
323
324 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 /* :TODO: show card ID */
332 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 s = "c\n";
336 ce->setResult (GPG_CARDRES_CANCEL);
337 WriteFile ((HANDLE)fd, s, strlen (s), &n, NULL);
338 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 GpgCardEdit::setPIN (const char *_pin)
393 {
394 this->pin = _pin;
395 }
396
397
398 /* Set the admin PIN for the object to @admin_pin. */
399 void
400 GpgCardEdit::setAdminPIN (const char *_admin_pin)
401 {
402 this->admin_pin = _admin_pin;
403 }
404
405
406 /* Set the new user PIN for the object to @new_pin. */
407 void
408 GpgCardEdit::setNewPIN (const char *_new_pin)
409 {
410 this->pin_new = _new_pin;
411 }
412
413
414 /* Set the passphrase needed when generating a key to @pass. */
415 void
416 GpgCardEdit::setKeygenPassphrase (const char *_pass)
417 {
418 this->keygen.pass = _pass;
419 }
420
421
422 /* Set the callback to @cb and the hook value to @cb_value. */
423 void
424 GpgCardEdit::setCallback (const char* (*_cb)(int code, void *opaque),
425 void *_cb_value)
426 {
427 this->cb_value = _cb_value;
428 this->card_cb = _cb;
429 }
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 gpg_card_t card = NULL;
441 char buf[200];
442
443 if (!r_card)
444 return gpg_error (GPG_ERR_INV_ARG);
445 *r_card = NULL;
446
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, DIM (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 GpgCardEdit::genKey (int flags,
492 const char *name, const char *email, const char *comment,
493 long valid, char **r_key_fpr)
494 {
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 sprintf (this->keygen.expdate, "%lu", valid);
519
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 GpgCardEdit::changePIN (int _type)
536 {
537 gpgme_error_t err;
538
539 if (!this->pin_new)
540 return gpg_error (GPG_ERR_INV_ARG);
541
542 if (!_type) {
543 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 this->type = _type;
552 /* 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 /* Update the given and the surname on the card. */
563 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
579 /* Update the given URL on the card. */
580 gpgme_error_t
581 GpgCardEdit::updateURL (const char *_url)
582 {
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 this->edit.keyurl = _url;
590
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
612 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 gpgme_error_t err = 0;
649
650 if (!this->pin)
651 return gpg_error (GPG_ERR_INV_OBJ);
652
653 return err;
654 }
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