mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-17 14:07:03 +01:00
2005-03-29 Moritz Schulte <moritz@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.
This commit is contained in:
parent
fde76a2cf8
commit
9476729709
@ -1,3 +1,11 @@
|
|||||||
|
2005-03-29 Moritz Schulte <moritz@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@g10code.com>
|
2005-02-25 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* app-openpgp.c (get_public_key): Make sure not to return negative
|
* app-openpgp.c (get_public_key): Make sure not to return negative
|
||||||
|
@ -776,6 +776,263 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
|
|||||||
return rc;
|
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
|
/* 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
|
the APP handle. On error that field gets cleared. If we already
|
||||||
@ -875,31 +1132,76 @@ get_public_key (app_t app, int keyno)
|
|||||||
e = ebuf;
|
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
|
else
|
||||||
{
|
{
|
||||||
/* Due to a design problem in v1.0 cards we can't get the public
|
/* 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.
|
key out of these cards without doing a verify on CHV3.
|
||||||
Clearly that is not an option and thus we try to locate the
|
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;
|
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:
|
leave:
|
||||||
/* Set a flag to indicate that we tried to read the key. */
|
/* Set a flag to indicate that we tried to read the key. */
|
||||||
app->app_local->pk[keyno].read_done = 1;
|
app->app_local->pk[keyno].read_done = 1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user