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

Contents of /trunk/Src/wptCardEdit.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 26 - (show annotations)
Mon Oct 17 08:49:30 2005 UTC (19 years, 4 months ago) by twoaday
File size: 15471 byte(s)
More bug fixes all over the place.
See ChangeLog for details.

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26