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

Contents of /trunk/Src/wptCardEdit.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 36 - (show 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 /* 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