1 /* findkey.c - locate the secret key
2 * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG 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.
11 * GnuPG 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.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
35 /* Helper to pass data to the check callback of the unprotect function. */
36 struct try_unprotect_arg_s
{
37 const unsigned char *protected_key
;
38 unsigned char *unprotected_key
;
42 /* Write an S-expression formatted key to our key storage. With FORCE
43 pased as true an existsing key with the given GRIP will get
46 agent_write_private_key (const unsigned char *grip
,
47 const void *buffer
, size_t length
, int force
)
55 for (i
=0; i
< 20; i
++)
56 sprintf (hexgrip
+2*i
, "%02X", grip
[i
]);
57 strcpy (hexgrip
+40, ".key");
59 fname
= make_filename (opt
.homedir
, GNUPG_PRIVATE_KEYS_DIR
, hexgrip
, NULL
);
61 if (!force
&& !access (fname
, F_OK
))
63 log_error ("secret key file `%s' already exists\n", fname
);
65 return gpg_error (GPG_ERR_GENERAL
);
68 /* In FORCE mode we would like to create FNAME but only if it does
69 not already exist. We cannot make this guarantee just using
70 POSIX (GNU provides the "x" opentype for fopen, however, this is
71 not portable). Thus, we use the more flexible open function and
72 then use fdopen to obtain a stream. */
73 fd
= open (fname
, force
? (O_CREAT
| O_TRUNC
| O_WRONLY
)
74 : (O_CREAT
| O_EXCL
| O_WRONLY
),
76 #ifndef HAVE_W32_SYSTEM
84 fp
= fdopen (fd
, "wb");
95 gpg_error_t tmperr
= gpg_error (gpg_err_code_from_errno (errno
));
96 log_error ("can't create `%s': %s\n", fname
, strerror (errno
));
101 if (fwrite (buffer
, length
, 1, fp
) != 1)
103 gpg_error_t tmperr
= gpg_error (gpg_err_code_from_errno (errno
));
104 log_error ("error writing `%s': %s\n", fname
, strerror (errno
));
112 gpg_error_t tmperr
= gpg_error (gpg_err_code_from_errno (errno
));
113 log_error ("error closing `%s': %s\n", fname
, strerror (errno
));
124 /* Callback function to try the unprotection from the passpharse query
127 try_unprotect_cb (struct pin_entry_info_s
*pi
)
129 struct try_unprotect_arg_s
*arg
= pi
->check_cb_arg
;
132 assert (!arg
->unprotected_key
);
133 return agent_unprotect (arg
->protected_key
, pi
->pin
,
134 &arg
->unprotected_key
, &dummy
);
138 /* Modify a Key description, replacing certain special format
139 characters. List of currently supported replacements:
141 %% - Replaced by a single %
142 %c - Replaced by the content of COMMENT.
144 The functions returns 0 on success or an error code. On success a
145 newly allocated string is stored at the address of RESULT.
148 modify_description (const char *in
, const char *comment
, char **result
)
150 size_t comment_length
;
157 comment_length
= strlen (comment
);
158 in_len
= strlen (in
);
160 /* First pass calculates the length, second pass does the actual
164 for (pass
=0; pass
< 2; pass
++)
167 for (i
= 0; i
< in_len
; i
++)
181 case 'c': /* Comment. */
184 memcpy (out
, comment
, comment_length
);
185 out
+= comment_length
;
188 out_len
+= comment_length
;
191 default: /* Invalid special sequences are kept as they are. */
202 else if (in
[i
] == '%')
215 *result
= out
= xtrymalloc (out_len
+ 1);
217 return gpg_error_from_errno (errno
);
222 assert (*result
+ out_len
== out
);
228 /* Unprotect the canconical encoded S-expression key in KEYBUF. GRIP
229 should be the hex encoded keygrip of that key to be used with the
230 caching mechanism. DESC_TEXT may be set to override the default
231 description used for the pinentry. */
233 unprotect (CTRL ctrl
, const char *desc_text
,
234 unsigned char **keybuf
, const unsigned char *grip
, int ignore_cache
)
236 struct pin_entry_info_s
*pi
;
237 struct try_unprotect_arg_s arg
;
239 unsigned char *result
;
243 for (i
=0; i
< 20; i
++)
244 sprintf (hexgrip
+2*i
, "%02X", grip
[i
]);
247 /* First try to get it from the cache - if there is none or we can't
248 unprotect it, we fall back to ask the user */
252 const char *pw
= agent_get_cache (hexgrip
, &cache_marker
);
255 rc
= agent_unprotect (*keybuf
, pw
, &result
, &resultlen
);
256 agent_unlock_cache_entry (&cache_marker
);
267 pi
= gcry_calloc_secure (1, sizeof (*pi
) + 100);
269 return gpg_error_from_errno (errno
);
270 pi
->max_length
= 100;
271 pi
->min_digits
= 0; /* we want a real passphrase */
274 pi
->check_cb
= try_unprotect_cb
;
275 arg
.protected_key
= *keybuf
;
276 arg
.unprotected_key
= NULL
;
277 pi
->check_cb_arg
= &arg
;
279 rc
= agent_askpin (ctrl
, desc_text
, NULL
, pi
);
282 assert (arg
.unprotected_key
);
283 agent_put_cache (hexgrip
, pi
->pin
, 0);
285 *keybuf
= arg
.unprotected_key
;
292 /* Read the key identified by GRIP from the private key directory and
293 return it as an gcrypt S-expression object in RESULT. On failure
294 returns an error code and stores NULL at RESULT. */
296 read_key_file (const unsigned char *grip
, gcry_sexp_t
*result
)
303 size_t buflen
, erroff
;
305 char hexgrip
[40+4+1];
309 for (i
=0; i
< 20; i
++)
310 sprintf (hexgrip
+2*i
, "%02X", grip
[i
]);
311 strcpy (hexgrip
+40, ".key");
313 fname
= make_filename (opt
.homedir
, GNUPG_PRIVATE_KEYS_DIR
, hexgrip
, NULL
);
314 fp
= fopen (fname
, "rb");
317 rc
= gpg_error_from_errno (errno
);
318 log_error ("can't open `%s': %s\n", fname
, strerror (errno
));
323 if (fstat (fileno(fp
), &st
))
325 rc
= gpg_error_from_errno (errno
);
326 log_error ("can't stat `%s': %s\n", fname
, strerror (errno
));
333 buf
= xtrymalloc (buflen
+1);
334 if (!buf
|| fread (buf
, buflen
, 1, fp
) != 1)
336 rc
= gpg_error_from_errno (errno
);
337 log_error ("error reading `%s': %s\n", fname
, strerror (errno
));
344 /* Convert the file into a gcrypt S-expression object. */
345 rc
= gcry_sexp_sscan (&s_skey
, &erroff
, buf
, buflen
);
351 log_error ("failed to build S-Exp (off=%u): %s\n",
352 (unsigned int)erroff
, gpg_strerror (rc
));
360 /* Return the secret key as an S-Exp in RESULT after locating it using
361 the grip. Returns NULL in RESULT if the operation should be
362 diverted to a token; SHADOW_INFO will point then to an allocated
363 S-Expression with the shadow_info part from the file. With
364 IGNORE_CACHE passed as true the passphrase is not taken from the
365 cache. DESC_TEXT may be set to present a custom description for the
368 agent_key_from_file (ctrl_t ctrl
, const char *desc_text
,
369 const unsigned char *grip
, unsigned char **shadow_info
,
370 int ignore_cache
, gcry_sexp_t
*result
)
374 size_t len
, buflen
, erroff
;
376 int got_shadow_info
= 0;
382 rc
= read_key_file (grip
, &s_skey
);
386 /* For use with the protection functions we also need the key as an
387 canonical encoded S-expression in abuffer. Create this buffer
389 len
= gcry_sexp_sprint (s_skey
, GCRYSEXP_FMT_CANON
, NULL
, 0);
391 buf
= xtrymalloc (len
);
394 rc
= gpg_error_from_errno (errno
);
395 gcry_sexp_release (s_skey
);
398 len
= gcry_sexp_sprint (s_skey
, GCRYSEXP_FMT_CANON
, buf
, len
);
402 switch (agent_private_key_type (buf
))
404 case PRIVATE_KEY_CLEAR
:
405 break; /* no unprotection needed */
406 case PRIVATE_KEY_PROTECTED
:
408 gcry_sexp_t comment_sexp
;
409 size_t comment_length
;
410 char *desc_text_final
;
411 const char *comment
= NULL
;
413 /* Note, that we will take the comment as a C string for
414 display purposes; i.e. all stuff beyond a Nul character is
416 comment_sexp
= gcry_sexp_find_token (s_skey
, "comment", 0);
418 comment
= gcry_sexp_nth_data (comment_sexp
, 1, &comment_length
);
425 desc_text_final
= NULL
;
428 if (comment
[comment_length
])
430 /* Not a C-string; create one. We might here allocate
431 more than actually displayed but well, that
432 shouldn't be a problem. */
433 char *tmp
= xtrymalloc (comment_length
+1);
435 rc
= gpg_error_from_errno (errno
);
438 memcpy (tmp
, comment
, comment_length
);
439 tmp
[comment_length
] = 0;
440 rc
= modify_description (desc_text
, tmp
, &desc_text_final
);
445 rc
= modify_description (desc_text
, comment
, &desc_text_final
);
450 rc
= unprotect (ctrl
, desc_text_final
, &buf
, grip
, ignore_cache
);
452 log_error ("failed to unprotect the secret key: %s\n",
456 gcry_sexp_release (comment_sexp
);
457 xfree (desc_text_final
);
460 case PRIVATE_KEY_SHADOWED
:
463 const unsigned char *s
;
466 rc
= agent_get_shadow_info (buf
, &s
);
469 n
= gcry_sexp_canon_len (s
, 0, NULL
,NULL
);
471 *shadow_info
= xtrymalloc (n
);
476 memcpy (*shadow_info
, s
, n
);
482 log_error ("get_shadow_info failed: %s\n", gpg_strerror (rc
));
485 rc
= gpg_error (GPG_ERR_UNUSABLE_SECKEY
);
488 log_error ("invalid private key format\n");
489 rc
= gpg_error (GPG_ERR_BAD_SECKEY
);
492 gcry_sexp_release (s_skey
);
494 if (rc
|| got_shadow_info
)
500 buflen
= gcry_sexp_canon_len (buf
, 0, NULL
, NULL
);
501 rc
= gcry_sexp_sscan (&s_skey
, &erroff
, buf
, buflen
);
502 wipememory (buf
, buflen
);
506 log_error ("failed to build S-Exp (off=%u): %s\n",
507 (unsigned int)erroff
, gpg_strerror (rc
));
517 /* Return the public key for the keygrip GRIP. The result is stored
518 at RESULT. This function extracts the public key from the private
519 key database. On failure an error code is returned and NULL stored
522 agent_public_key_from_file (ctrl_t ctrl
,
523 const unsigned char *grip
,
528 const char *algoname
;
529 gcry_sexp_t uri_sexp
, comment_sexp
;
530 const char *uri
, *comment
;
531 size_t uri_length
, comment_length
;
533 void *args
[4+2+2+1]; /* Size is max. # of elements + 2 for uri + 2
534 for comment + end-of-list. */
536 gcry_sexp_t list
, l2
;
545 rc
= read_key_file (grip
, &s_skey
);
549 list
= gcry_sexp_find_token (s_skey
, "shadowed-private-key", 0 );
551 list
= gcry_sexp_find_token (s_skey
, "protected-private-key", 0 );
553 list
= gcry_sexp_find_token (s_skey
, "private-key", 0 );
556 log_error ("invalid private key format\n");
557 gcry_sexp_release (s_skey
);
558 return gpg_error (GPG_ERR_BAD_SECKEY
);
561 l2
= gcry_sexp_cadr (list
);
562 gcry_sexp_release (list
);
564 name
= gcry_sexp_nth_data (list
, 0, &n
);
565 if (n
==3 && !memcmp (name
, "rsa", 3))
570 else if (n
==3 && !memcmp (name
, "dsa", 3))
575 else if (n
==3 && !memcmp (name
, "elg", 3))
582 log_error ("unknown private key algorithm\n");
583 gcry_sexp_release (list
);
584 gcry_sexp_release (s_skey
);
585 return gpg_error (GPG_ERR_BAD_SECKEY
);
588 /* Allocate an array for the parameters and copy them out of the
589 secret key. FIXME: We should have a generic copy function. */
590 array
= xtrycalloc (strlen(elems
) + 1, sizeof *array
);
593 rc
= gpg_error_from_errno (errno
);
594 gcry_sexp_release (list
);
595 gcry_sexp_release (s_skey
);
599 for (idx
=0, s
=elems
; *s
; s
++, idx
++ )
601 l2
= gcry_sexp_find_token (list
, s
, 1);
604 /* Required parameter not found. */
605 for (i
=0; i
<idx
; i
++)
606 gcry_mpi_release (array
[i
]);
608 gcry_sexp_release (list
);
609 gcry_sexp_release (s_skey
);
610 return gpg_error (GPG_ERR_BAD_SECKEY
);
612 array
[idx
] = gcry_sexp_nth_mpi (l2
, 1, GCRYMPI_FMT_USG
);
613 gcry_sexp_release (l2
);
616 /* Required parameter is invalid. */
617 for (i
=0; i
<idx
; i
++)
618 gcry_mpi_release (array
[i
]);
620 gcry_sexp_release (list
);
621 gcry_sexp_release (s_skey
);
622 return gpg_error (GPG_ERR_BAD_SECKEY
);
625 gcry_sexp_release (list
);
630 uri_sexp
= gcry_sexp_find_token (s_skey
, "uri", 0);
632 uri
= gcry_sexp_nth_data (uri_sexp
, 1, &uri_length
);
636 comment_sexp
= gcry_sexp_find_token (s_skey
, "comment", 0);
638 comment
= gcry_sexp_nth_data (comment_sexp
, 1, &comment_length
);
640 gcry_sexp_release (s_skey
);
644 /* FIXME: The following thing is pretty ugly code; we should
645 investigate how to make it cleaner. Probably code to handle
646 canonical S-expressions in a memory buffer is better suioted for
647 such a task. After all that is what we do in protect.c. Neeed
648 to find common patterns and write a straightformward API to use
650 assert (sizeof (size_t) <= sizeof (void*));
652 format
= xtrymalloc (15+7*strlen (elems
)+10+15+1+1);
655 rc
= gpg_error_from_errno (errno
);
656 for (i
=0; array
[i
]; i
++)
657 gcry_mpi_release (array
[i
]);
659 gcry_sexp_release (uri_sexp
);
660 gcry_sexp_release (comment_sexp
);
665 p
= stpcpy (stpcpy (format
, "(public-key("), algoname
);
666 for (idx
=0, s
=elems
; *s
; s
++, idx
++ )
670 p
= stpcpy (p
, " %m)");
671 assert (argidx
< DIM (args
));
672 args
[argidx
++] = array
[idx
];
677 p
= stpcpy (p
, "(uri %b)");
678 assert (argidx
+1 < DIM (args
));
679 args
[argidx
++] = (void *)uri_length
;
680 args
[argidx
++] = (void *)uri
;
684 p
= stpcpy (p
, "(comment %b)");
685 assert (argidx
+1 < DIM (args
));
686 args
[argidx
++] = (void *)comment_length
;
687 args
[argidx
++] = (void*)comment
;
691 assert (argidx
< DIM (args
));
694 rc
= gcry_sexp_build_array (&list
, NULL
, format
, args
);
696 for (i
=0; array
[i
]; i
++)
697 gcry_mpi_release (array
[i
]);
699 gcry_sexp_release (uri_sexp
);
700 gcry_sexp_release (comment_sexp
);
709 /* Return the secret key as an S-Exp after locating it using the grip.
710 Returns NULL if key is not available. 0 = key is available */
712 agent_key_available (const unsigned char *grip
)
716 char hexgrip
[40+4+1];
718 for (i
=0; i
< 20; i
++)
719 sprintf (hexgrip
+2*i
, "%02X", grip
[i
]);
720 strcpy (hexgrip
+40, ".key");
722 fname
= make_filename (opt
.homedir
, GNUPG_PRIVATE_KEYS_DIR
, hexgrip
, NULL
);
723 i
= !access (fname
, R_OK
)? 0 : -1;