GNUPG-1-9-BRANCH gnupg/scd (ChangeLog app-openpgp.c)
cvs user mo
cvs at cvs.gnupg.org
Tue Mar 29 22:31:35 CEST 2005
Date: Tuesday, March 29, 2005 @ 22:46:18
Author: mo
Path: /cvs/gnupg/gnupg/scd
Tag: GNUPG-1-9-BRANCH
Modified: ChangeLog app-openpgp.c
2005-03-29 Moritz Schulte <moritz at g10code.com>
* app-openpgp.c (retrieve_fpr_from_card): New function.
(retrieve_next_token): New function.
(retrieve_key_material): New function.
(get_public_key): Implement retrival of key through expernal
helper (gpg) in case the openpgp card is not cooperative enough.
---------------+
ChangeLog | 8 +
app-openpgp.c | 332 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 325 insertions(+), 15 deletions(-)
Index: gnupg/scd/ChangeLog
diff -u gnupg/scd/ChangeLog:1.25.2.70 gnupg/scd/ChangeLog:1.25.2.71
--- gnupg/scd/ChangeLog:1.25.2.70 Fri Feb 25 17:14:54 2005
+++ gnupg/scd/ChangeLog Tue Mar 29 22:46:18 2005
@@ -1,3 +1,11 @@
+2005-03-29 Moritz Schulte <moritz at g10code.com>
+
+ * app-openpgp.c (retrieve_fpr_from_card): New function.
+ (retrieve_next_token): New function.
+ (retrieve_key_material): New function.
+ (get_public_key): Implement retrival of key through expernal
+ helper (gpg) in case the openpgp card is not cooperative enough.
+
2005-02-25 Werner Koch <wk at g10code.com>
* app-openpgp.c (get_public_key): Make sure not to return negative
Index: gnupg/scd/app-openpgp.c
diff -u gnupg/scd/app-openpgp.c:1.9.2.27 gnupg/scd/app-openpgp.c:1.9.2.28
--- gnupg/scd/app-openpgp.c:1.9.2.27 Fri Feb 25 17:14:54 2005
+++ gnupg/scd/app-openpgp.c Tue Mar 29 22:46:18 2005
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: app-openpgp.c,v 1.9.2.27 2005/02/25 16:14:54 wk Exp $
+ * $Id: app-openpgp.c,v 1.9.2.28 2005/03/29 20:46:18 mo Exp $
*/
#include <config.h>
@@ -776,6 +776,263 @@
return rc;
}
+/* Retrieve the fingerprint from the card inserted in SLOT and write
+ the according hex representation (40 hex digits plus NUL character)
+ to FPR. */
+static gpg_error_t
+retrieve_fpr_from_card (int slot, char *fpr)
+{
+ const unsigned char *value;
+ unsigned char *data;
+ size_t data_n;
+ gpg_error_t err;
+ size_t value_n;
+ unsigned int i;
+
+ data = NULL;
+
+ err = iso7816_get_data (slot, 0x6E, &data, &data_n);
+ if (err)
+ /* FIXME */
+ goto out;
+
+ value = find_tlv (data, data_n, 0x00C5, &value_n);
+ if (! (value
+ && (! (value_n > (data_n - (value - data))))
+ && (value_n >= 60))) /* FIXME: Shouldn't this be "== 60"? */
+ {
+ /* FIXME? */
+ err = gpg_error (GPG_ERR_CARD); /* */
+ goto out;
+ }
+
+ /* Copy out third key FPR. */
+ for (i = 0; i < 20; i++)
+ sprintf (fpr + (i * 2), "%02X", (value + (2 * 20))[i]);
+
+ out:
+
+ xfree (data);
+
+ return err;
+}
+
+/* Retrieve the next token from S, using ":" as delimiter. */
+static char *
+retrieve_next_token (char *s)
+{
+ char *p;
+
+ p = strtok (s, ":");
+ if (! p)
+ log_error ("error while extracting token\n");
+
+ return p;
+}
+
+/* Retrieve the secret key material for the key, whose fingerprint is
+ FPR, from gpg output, which can be read through the stream FP. The
+ RSA modulus will be stored in m/mlen, the secret exponent in
+ e/elen. Return zero on success, one on failure. */
+static int
+retrieve_key_material (FILE *fp, const char *fpr,
+ const unsigned char **m, size_t *mlen,
+ const unsigned char **e, size_t *elen)
+{
+ size_t line_size;
+ ssize_t line_ret;
+ char *line;
+ int ret;
+ int found_key;
+ char *token;
+ int pkd_n;
+ unsigned char *m_new;
+ unsigned char *e_new;
+ size_t m_new_n;
+ size_t e_new_n;
+ int is_rsa;
+ gcry_mpi_t mpi;
+ gcry_error_t err;
+ size_t max_length;
+
+ line_size = 0;
+ line = NULL;
+ found_key = 0;
+ pkd_n = 0;
+ m_new = NULL;
+ e_new = NULL;
+ mpi = NULL;
+ ret = 0;
+
+ while (1)
+ {
+ /* FIXME? */
+ max_length = 1024;
+ line_ret = read_line (fp, &line, &line_size, &max_length);
+ if (line_ret < 0)
+ {
+ ret = 1;
+ break;
+ }
+ if (! line_ret)
+ /* EOF. */
+ /* FIXME? */
+ break;
+
+ token = retrieve_next_token (line);
+ if (! found_key)
+ {
+ /* Key not found yet, search for key entry. */
+ if ((! strcmp (token, "pub")) || (! strcmp (token, "sub")))
+ {
+ /* Reached next key entry, parse it. */
+
+ /* This is the trust level (right, FIXME?). */
+ token = retrieve_next_token (NULL);
+ if (! token)
+ {
+ ret = 1;
+ break;
+ }
+
+ /* This is the size. */
+ token = retrieve_next_token (NULL);
+ if (! token)
+ {
+ ret = 1;
+ break;
+ }
+
+ /* This is the algorithm (right, FIXME?). */
+ token = retrieve_next_token (NULL);
+ if (! token)
+ {
+ ret = 1;
+ break;
+ }
+ is_rsa = ! strcmp (token, "1");
+
+ /* This is the fingerprint. */
+ token = retrieve_next_token (NULL);
+ if (! token)
+ {
+ ret = 1;
+ break;
+ }
+
+ if (! strcmp (token, fpr))
+ {
+ /* Found our key. */
+ if (! is_rsa)
+ {
+ /* FIXME. */
+ ret = 1;
+ break;
+ }
+ found_key = 1;
+ }
+ }
+ }
+ else
+ {
+ if (! strcmp (token, "sub"))
+ /* Next key entry, break. */
+ break;
+
+ if (! strcmp (token, "pkd"))
+ {
+ if ((pkd_n == 0) || (pkd_n == 1))
+ {
+ /* This is the pkd index. */
+ token = retrieve_next_token (NULL);
+ if (! token)
+ {
+ /* FIXME. */
+ ret = 1;
+ break;
+ }
+
+ /* This is the pkd size. */
+ token = retrieve_next_token (NULL);
+ if (! token)
+ {
+ /* FIXME. */
+ ret = 1;
+ break;
+ }
+
+ /* This is the pkd mpi. */
+ token = retrieve_next_token (NULL);
+ if (! token)
+ {
+ /* FIXME. */
+ ret = 1;
+ break;
+ }
+
+ err = gcry_mpi_scan (&mpi, GCRYMPI_FMT_HEX, token, 0, NULL);
+ if (err)
+ {
+ log_error ("error while converting pkd %i from hex: %s\n",
+ pkd_n, gcry_strerror (err));
+ ret = 1;
+ break;
+ }
+
+ if (pkd_n == 0)
+ err = gcry_mpi_aprint (GCRYMPI_FMT_STD,
+ &m_new, &m_new_n, mpi);
+ else
+ err = gcry_mpi_aprint (GCRYMPI_FMT_STD,
+ &e_new, &e_new_n, mpi);
+ if (err)
+ {
+ log_error ("error while converting pkd %i to std: %s\n",
+ pkd_n, gcry_strerror (err));
+ ret = 1;
+ break;
+ }
+ gcry_mpi_release (mpi);
+ mpi = NULL;
+ pkd_n++;
+ }
+ else
+ {
+ /* Too many pkd entries. */
+ /* FIXME */
+ ret = 1;
+ break;
+ }
+ }
+ }
+ }
+ if (ret)
+ goto out;
+
+ if (pkd_n < 2)
+ {
+ /* Not enough pkds retrieved. */
+ ret = 1;
+ goto out;
+ }
+
+ *m = m_new;
+ *mlen = m_new_n;
+ *e = e_new;
+ *elen = e_new_n;
+
+ out:
+
+ if (ret)
+ {
+ gcry_free (m_new);
+ gcry_free (e_new);
+ }
+ gcry_mpi_release (mpi);
+ gcry_free (line);
+
+ return ret;
+}
/* Get the public key for KEYNO and store it as an S-expresion with
the APP handle. On error that field gets cleared. If we already
@@ -875,30 +1132,75 @@
e = ebuf;
}
-
- err = gcry_sexp_build (&sexp, NULL,
- "(public-key (rsa (n %b) (e %b)))",
- (int)mlen, m,(int)elen, e);
- if (err)
- {
- log_error ("error formatting the key into an S-expression: %s\n",
- gpg_strerror (err));
- goto leave;
- }
- app->app_local->pk[keyno].key = sexp;
-
}
else
{
/* Due to a design problem in v1.0 cards we can't get the public
key out of these cards without doing a verify on CHV3.
Clearly that is not an option and thus we try to locate the
- key using an external helper. */
+ key using an external helper.
+
+ The helper we use here is gpg itself, which should know about
+ the key in any case. */
+
+ char fpr_long[41];
+ char *fpr = fpr_long + 24;
+ char *command;
+ FILE *fp;
+ int ret;
+
+ command = NULL;
+
+ err = retrieve_fpr_from_card (app->slot, fpr_long);
+ if (err)
+ {
+ log_error ("error while retrieving fpr from card: %s\n",
+ gpg_strerror (err));
+ goto leave;
+ }
+
+ ret = asprintf (&command,
+ "gpg --list-keys --with-colons --with-key-data '%s'",
+ fpr_long);
+ if (ret < 0)
+ {
+ err = gpg_error_from_errno (errno);
+ log_error ("error while creating pipe command "
+ "for retrieving key: %s\n", gpg_strerror (err));
+ goto leave;
+ }
+
+ fp = popen (command, "r");
+ if (! fp)
+ {
+ err = gpg_error_from_errno (errno);
+ log_error ("error while creating pipe: %s\n", gpg_strerror (err));
+ goto leave;
+ }
+
+ ret = retrieve_key_material (fp, fpr, &m, &mlen, &e, &elen);
+ fclose (fp);
+ if (ret)
+ {
+ /* FIXME? */
+ err = gpg_error (GPG_ERR_INTERNAL);
+ log_error ("error while retrieving key material through pipe\n");
+ goto leave;
+ }
buffer = NULL;
- /* FIXME */
+ }
+ err = gcry_sexp_build (&sexp, NULL,
+ "(public-key (rsa (n %b) (e %b)))",
+ (int)mlen, m,(int)elen, e);
+ if (err)
+ {
+ log_error ("error formatting the key into an S-expression: %s\n",
+ gpg_strerror (err));
+ goto leave;
}
+ app->app_local->pk[keyno].key = sexp;
leave:
/* Set a flag to indicate that we tried to read the key. */
More information about the Gnupg-commits
mailing list