mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-02 22:46:30 +02:00
Import OpenPGP keys into the agent.
This commit is contained in:
parent
71bc88fbae
commit
87fac99112
23 changed files with 1669 additions and 282 deletions
|
@ -1,3 +1,18 @@
|
|||
2010-08-31 Werner Koch <wk@g10code.com>
|
||||
|
||||
* pksign.c (do_encode_dsa): Fix sign problem.
|
||||
* findkey.c (agent_is_dsa_key): Adjust to actual usage.
|
||||
|
||||
2010-08-30 Werner Koch <wk@g10code.com>
|
||||
|
||||
* protect.c (s2k_hash_passphrase): New public function.
|
||||
|
||||
2010-08-27 Werner Koch <wk@g10code.com>
|
||||
|
||||
* command.c (cmd_import_key): Support OpenPGP keys.
|
||||
* cvt-openpgp.h, cvt-openpgp.c: New. Some of the code is based on
|
||||
code taken from g10/seckey-cert.c.
|
||||
|
||||
2010-08-26 Werner Koch <wk@g10code.com>
|
||||
|
||||
* command-ssh.c (open_control_file): Use estream to create the file.
|
||||
|
|
|
@ -46,6 +46,7 @@ gpg_agent_SOURCES = \
|
|||
protect.c \
|
||||
trustlist.c \
|
||||
divert-scd.c \
|
||||
cvt-openpgp.c cvt-openpgp.h \
|
||||
call-scd.c \
|
||||
learncard.c
|
||||
|
||||
|
|
|
@ -171,8 +171,8 @@ struct pin_entry_info_s
|
|||
int with_qualitybar; /* Set if the quality bar should be displayed. */
|
||||
int (*check_cb)(struct pin_entry_info_s *); /* CB used to check the PIN */
|
||||
void *check_cb_arg; /* optional argument which might be of use in the CB */
|
||||
const char *cb_errtext; /* used by the cb to displaye a specific error */
|
||||
size_t max_length; /* allocated length of the buffer */
|
||||
const char *cb_errtext; /* used by the cb to display a specific error */
|
||||
size_t max_length; /* allocated length of the buffer */
|
||||
char pin[1];
|
||||
};
|
||||
|
||||
|
@ -306,6 +306,11 @@ int agent_get_shadow_info (const unsigned char *shadowkey,
|
|||
unsigned char const **shadow_info);
|
||||
gpg_error_t parse_shadow_info (const unsigned char *shadow_info,
|
||||
char **r_hexsn, char **r_idstr);
|
||||
gpg_error_t s2k_hash_passphrase (const char *passphrase, int hashalgo,
|
||||
int s2kmode,
|
||||
const unsigned char *s2ksalt,
|
||||
unsigned int s2kcount,
|
||||
unsigned char *key, size_t keylen);
|
||||
|
||||
|
||||
/*-- trustlist.c --*/
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
#include "agent.h"
|
||||
#include <assuan.h>
|
||||
#include "i18n.h"
|
||||
|
||||
#include "cvt-openpgp.h"
|
||||
|
||||
|
||||
/* Maximum allowed size of the inquired ciphertext. */
|
||||
|
@ -357,6 +357,12 @@ leave_cmd (assuan_context_t ctx, gpg_error_t err)
|
|||
const char *name = assuan_get_command_name (ctx);
|
||||
if (!name)
|
||||
name = "?";
|
||||
|
||||
/* Most code from common/ does not know the error source, thus
|
||||
we fix this here. */
|
||||
if (gpg_err_source (err) == GPG_ERR_SOURCE_UNKNOWN)
|
||||
err = gpg_err_make (GPG_ERR_SOURCE_DEFAULT, gpg_err_code (err));
|
||||
|
||||
if (gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT)
|
||||
log_error ("command '%s' failed: %s\n", name,
|
||||
gpg_strerror (err));
|
||||
|
@ -566,8 +572,8 @@ cmd_sigkey (assuan_context_t ctx, char *line)
|
|||
static const char hlp_setkeydesc[] =
|
||||
"SETKEYDESC plus_percent_escaped_string\n"
|
||||
"\n"
|
||||
"Set a description to be used for the next PKSIGN, PKDECRYPT or EXPORT_KEY\n"
|
||||
"operation if this operation requires the entry of a passphrase. If\n"
|
||||
"Set a description to be used for the next PKSIGN, PKDECRYPT, IMPORT_KEY\n"
|
||||
"or EXPORT_KEY operation if this operation requires a passphrase. If\n"
|
||||
"this command is not used a default text will be used. Note, that\n"
|
||||
"this description implictly selects the label used for the entry\n"
|
||||
"box; if the string contains the string PIN (which in general will\n"
|
||||
|
@ -575,8 +581,8 @@ static const char hlp_setkeydesc[] =
|
|||
"\"passphrase\" is used. The description string should not contain\n"
|
||||
"blanks unless they are percent or '+' escaped.\n"
|
||||
"\n"
|
||||
"The description is only valid for the next PKSIGN, PKDECRYPT or\n"
|
||||
"EXPORT_KEY operation.";
|
||||
"The description is only valid for the next PKSIGN, PKDECRYPT,\n"
|
||||
"IMPORT_KEY or EXPORT_KEY operation.";
|
||||
static gpg_error_t
|
||||
cmd_setkeydesc (assuan_context_t ctx, char *line)
|
||||
{
|
||||
|
@ -1478,6 +1484,7 @@ cmd_import_key (assuan_context_t ctx, char *line)
|
|||
unsigned char *finalkey = NULL;
|
||||
size_t finalkeylen;
|
||||
unsigned char grip[20];
|
||||
gcry_sexp_t openpgp_sexp = NULL;
|
||||
|
||||
(void)line;
|
||||
|
||||
|
@ -1528,20 +1535,58 @@ cmd_import_key (assuan_context_t ctx, char *line)
|
|||
|
||||
err = keygrip_from_canon_sexp (key, realkeylen, grip);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
if (!agent_key_available (grip))
|
||||
{
|
||||
err = gpg_error (GPG_ERR_EEXIST);
|
||||
goto leave;
|
||||
/* This might be due to an unsupported S-expression format.
|
||||
Check whether this is openpgp-private-key and trigger that
|
||||
import code. */
|
||||
if (!gcry_sexp_sscan (&openpgp_sexp, NULL, key, realkeylen))
|
||||
{
|
||||
const char *tag;
|
||||
size_t taglen;
|
||||
|
||||
tag = gcry_sexp_nth_data (openpgp_sexp, 0, &taglen);
|
||||
if (tag && taglen == 19 && !memcmp (tag, "openpgp-private-key", 19))
|
||||
;
|
||||
else
|
||||
{
|
||||
gcry_sexp_release (openpgp_sexp);
|
||||
openpgp_sexp = NULL;
|
||||
}
|
||||
}
|
||||
if (!openpgp_sexp)
|
||||
goto leave; /* Note that ERR is still set. */
|
||||
}
|
||||
|
||||
err = agent_ask_new_passphrase
|
||||
(ctrl, _("Please enter the passphrase to protect the "
|
||||
"imported object within the GnuPG system."),
|
||||
&passphrase);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
if (openpgp_sexp)
|
||||
{
|
||||
/* In most cases the key is encrypted and thus the conversion
|
||||
function from the OpenPGP format to our internal format will
|
||||
ask for a passphrase. That passphrase will be returned and
|
||||
used to protect the key using the same code as for regular
|
||||
key import. */
|
||||
|
||||
err = convert_openpgp (ctrl, openpgp_sexp, grip,
|
||||
ctrl->server_local->keydesc,
|
||||
&key, &passphrase);
|
||||
if (err)
|
||||
goto leave;
|
||||
realkeylen = gcry_sexp_canon_len (key, keylen, NULL, &err);
|
||||
if (!realkeylen)
|
||||
goto leave; /* Invalid canonical encoded S-expression. */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!agent_key_available (grip))
|
||||
err = gpg_error (GPG_ERR_EEXIST);
|
||||
else
|
||||
err = agent_ask_new_passphrase
|
||||
(ctrl, _("Please enter the passphrase to protect the "
|
||||
"imported object within the GnuPG system."),
|
||||
&passphrase);
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (passphrase)
|
||||
{
|
||||
|
@ -1553,11 +1598,14 @@ cmd_import_key (assuan_context_t ctx, char *line)
|
|||
err = agent_write_private_key (grip, key, realkeylen, 0);
|
||||
|
||||
leave:
|
||||
gcry_sexp_release (openpgp_sexp);
|
||||
xfree (finalkey);
|
||||
xfree (passphrase);
|
||||
xfree (key);
|
||||
gcry_cipher_close (cipherhd);
|
||||
xfree (wrappedkey);
|
||||
xfree (ctrl->server_local->keydesc);
|
||||
ctrl->server_local->keydesc = NULL;
|
||||
return leave_cmd (ctx, err);
|
||||
}
|
||||
|
||||
|
|
807
agent/cvt-openpgp.c
Normal file
807
agent/cvt-openpgp.c
Normal file
|
@ -0,0 +1,807 @@
|
|||
/* cvt-openpgp.c - Convert an OpenPGP key to our internal format.
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2006, 2009,
|
||||
* 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "agent.h"
|
||||
#include "i18n.h"
|
||||
#include "cvt-openpgp.h"
|
||||
|
||||
|
||||
/* Helper to pass data via the callback to do_unprotect. */
|
||||
struct try_do_unprotect_arg_s
|
||||
{
|
||||
int is_v4;
|
||||
int is_protected;
|
||||
int pubkey_algo;
|
||||
int protect_algo;
|
||||
char *iv;
|
||||
int ivlen;
|
||||
int s2k_mode;
|
||||
int s2k_algo;
|
||||
byte *s2k_salt;
|
||||
u32 s2k_count;
|
||||
u16 desired_csum;
|
||||
gcry_mpi_t *skey;
|
||||
size_t skeysize;
|
||||
int skeyidx;
|
||||
gcry_sexp_t *r_key;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Compute the keygrip from the public key and store it at GRIP. */
|
||||
static gpg_error_t
|
||||
get_keygrip (int pubkey_algo, gcry_mpi_t *pkey, unsigned char *grip)
|
||||
{
|
||||
gpg_error_t err;
|
||||
gcry_sexp_t s_pkey = NULL;
|
||||
|
||||
switch (pubkey_algo)
|
||||
{
|
||||
case GCRY_PK_DSA:
|
||||
err = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
|
||||
pkey[0], pkey[1], pkey[2], pkey[3]);
|
||||
break;
|
||||
|
||||
case GCRY_PK_ELG:
|
||||
case GCRY_PK_ELG_E:
|
||||
err = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(elg(p%m)(g%m)(y%m)))",
|
||||
pkey[0], pkey[1], pkey[2]);
|
||||
break;
|
||||
|
||||
case GCRY_PK_RSA:
|
||||
case GCRY_PK_RSA_E:
|
||||
case GCRY_PK_RSA_S:
|
||||
err = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
|
||||
break;
|
||||
|
||||
default:
|
||||
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!err && !gcry_pk_get_keygrip (s_pkey, grip))
|
||||
err = gpg_error (GPG_ERR_INTERNAL);
|
||||
|
||||
gcry_sexp_release (s_pkey);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Convert a secret key given as algorithm id and an array of key
|
||||
parameters into our s-expression based format. */
|
||||
static gpg_error_t
|
||||
convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
|
||||
{
|
||||
gpg_error_t err;
|
||||
gcry_sexp_t s_skey = NULL;
|
||||
|
||||
*r_key = NULL;
|
||||
|
||||
switch (pubkey_algo)
|
||||
{
|
||||
case GCRY_PK_DSA:
|
||||
err = gcry_sexp_build (&s_skey, NULL,
|
||||
"(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
|
||||
skey[0], skey[1], skey[2], skey[3], skey[4]);
|
||||
break;
|
||||
|
||||
case GCRY_PK_ELG:
|
||||
case GCRY_PK_ELG_E:
|
||||
err = gcry_sexp_build (&s_skey, NULL,
|
||||
"(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
|
||||
skey[0], skey[1], skey[2], skey[3]);
|
||||
break;
|
||||
|
||||
|
||||
case GCRY_PK_RSA:
|
||||
case GCRY_PK_RSA_E:
|
||||
case GCRY_PK_RSA_S:
|
||||
err = gcry_sexp_build (&s_skey, NULL,
|
||||
"(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
|
||||
skey[0], skey[1], skey[2], skey[3], skey[4],
|
||||
skey[5]);
|
||||
|
||||
default:
|
||||
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!err)
|
||||
*r_key = s_skey;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Hash the passphrase and set the key. */
|
||||
static gpg_error_t
|
||||
hash_passphrase_and_set_key (const char *passphrase,
|
||||
gcry_cipher_hd_t hd, int protect_algo,
|
||||
int s2k_mode, int s2k_algo,
|
||||
byte *s2k_salt, u32 s2k_count)
|
||||
{
|
||||
gpg_error_t err;
|
||||
unsigned char *key;
|
||||
size_t keylen;
|
||||
|
||||
keylen = gcry_cipher_get_algo_keylen (protect_algo);
|
||||
if (!keylen)
|
||||
return gpg_error (GPG_ERR_INTERNAL);
|
||||
|
||||
key = xtrymalloc_secure (keylen);
|
||||
if (!key)
|
||||
return gpg_error_from_syserror ();
|
||||
|
||||
err = s2k_hash_passphrase (passphrase,
|
||||
s2k_algo, s2k_mode, s2k_salt, s2k_count,
|
||||
key, keylen);
|
||||
if (!err)
|
||||
err = gcry_cipher_setkey (hd, key, keylen);
|
||||
|
||||
xfree (key);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static u16
|
||||
checksum (const unsigned char *p, unsigned int n)
|
||||
{
|
||||
u16 a;
|
||||
|
||||
for (a=0; n; n-- )
|
||||
a += *p++;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
/* Note that this function modified SKEY. SKEYSIZE is the allocated
|
||||
size of the array including the NULL item; this is used for a
|
||||
bounds check. On success a converted key is stored at R_KEY. */
|
||||
static int
|
||||
do_unprotect (const char *passphrase,
|
||||
int pkt_version, int pubkey_algo, int is_protected,
|
||||
gcry_mpi_t *skey, size_t skeysize,
|
||||
int protect_algo, void *protect_iv, size_t protect_ivlen,
|
||||
int s2k_mode, int s2k_algo, byte *s2k_salt, u32 s2k_count,
|
||||
u16 desired_csum, gcry_sexp_t *r_key)
|
||||
{
|
||||
gpg_error_t err;
|
||||
size_t npkey, nskey, skeylen;
|
||||
gcry_cipher_hd_t cipher_hd = NULL;
|
||||
u16 actual_csum;
|
||||
size_t nbytes;
|
||||
int i;
|
||||
gcry_mpi_t tmpmpi;
|
||||
|
||||
*r_key = NULL;
|
||||
|
||||
/* Count the actual number of MPIs is in the array and set the
|
||||
remainder to NULL for easier processing later on. */
|
||||
for (skeylen = 0; skey[skeylen]; skeylen++)
|
||||
;
|
||||
for (i=skeylen; i < skeysize; i++)
|
||||
skey[i] = NULL;
|
||||
|
||||
/* Check some args. */
|
||||
if (s2k_mode == 1001)
|
||||
{
|
||||
/* Stub key. */
|
||||
log_info (_("secret key parts are not available\n"));
|
||||
return gpg_error (GPG_ERR_UNUSABLE_SECKEY);
|
||||
}
|
||||
|
||||
if (gcry_pk_test_algo (pubkey_algo))
|
||||
{
|
||||
/* The algorithm numbers are Libgcrypt numbers but fortunately
|
||||
the OpenPGP algorithm numbers map one-to-one to the Libgcrypt
|
||||
numbers. */
|
||||
log_info (_("public key algorithm %d (%s) is not supported\n"),
|
||||
pubkey_algo, gcry_pk_algo_name (pubkey_algo));
|
||||
return gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
}
|
||||
|
||||
/* Get properties of the public key algorithm and do some
|
||||
consistency checks. Note that we need at least NPKEY+1 elements
|
||||
in the SKEY array. */
|
||||
if ( (err = gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NPKEY,
|
||||
NULL, &npkey))
|
||||
|| (err = gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NSKEY,
|
||||
NULL, &nskey)))
|
||||
return err;
|
||||
if (!npkey || npkey >= nskey)
|
||||
return gpg_error (GPG_ERR_INTERNAL);
|
||||
if (skeylen <= npkey)
|
||||
return gpg_error (GPG_ERR_MISSING_VALUE);
|
||||
if (nskey+1 >= skeysize)
|
||||
return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
|
||||
|
||||
/* Check whether SKEY is at all protected. If it is not protected
|
||||
merely verify the checksum. */
|
||||
if (!is_protected)
|
||||
{
|
||||
unsigned char *buffer;
|
||||
|
||||
actual_csum = 0;
|
||||
for (i=npkey; i < nskey; i++)
|
||||
{
|
||||
if (!skey[i] || gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_OPAQUE))
|
||||
return gpg_error (GPG_ERR_BAD_SECKEY);
|
||||
|
||||
err = gcry_mpi_print (GCRYMPI_FMT_PGP, NULL, 0, &nbytes, skey[i]);
|
||||
if (!err)
|
||||
{
|
||||
buffer = (gcry_is_secure (skey[i])?
|
||||
xtrymalloc_secure (nbytes) : xtrymalloc (nbytes));
|
||||
if (!buffer)
|
||||
return gpg_error_from_syserror ();
|
||||
err = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes,
|
||||
NULL, skey[i]);
|
||||
if (!err)
|
||||
actual_csum += checksum (buffer, nbytes);
|
||||
xfree (buffer);
|
||||
}
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (actual_csum != desired_csum)
|
||||
return gpg_error (GPG_ERR_CHECKSUM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if (gcry_cipher_test_algo (protect_algo))
|
||||
{
|
||||
/* The algorithm numbers are Libgcrypt numbers but fortunately
|
||||
the OpenPGP algorithm numbers map one-to-one to the Libgcrypt
|
||||
numbers. */
|
||||
log_info (_("protection algorithm %d (%s) is not supported\n"),
|
||||
protect_algo, gcry_cipher_algo_name (protect_algo));
|
||||
return gpg_error (GPG_ERR_CIPHER_ALGO);
|
||||
}
|
||||
|
||||
if (gcry_md_test_algo (s2k_algo))
|
||||
{
|
||||
log_info (_("protection hash algorithm %d (%s) is not supported\n"),
|
||||
s2k_algo, gcry_md_algo_name (s2k_algo));
|
||||
return gpg_error (GPG_ERR_DIGEST_ALGO);
|
||||
}
|
||||
|
||||
err = gcry_cipher_open (&cipher_hd, protect_algo,
|
||||
GCRY_CIPHER_MODE_CFB,
|
||||
(GCRY_CIPHER_SECURE
|
||||
| (protect_algo >= 100 ?
|
||||
0 : GCRY_CIPHER_ENABLE_SYNC)));
|
||||
if (err)
|
||||
{
|
||||
log_error ("failed to open cipher_algo %d: %s\n",
|
||||
protect_algo, gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
|
||||
err = hash_passphrase_and_set_key (passphrase, cipher_hd, protect_algo,
|
||||
s2k_mode, s2k_algo, s2k_salt, s2k_count);
|
||||
if (err)
|
||||
{
|
||||
gcry_cipher_close (cipher_hd);
|
||||
return err;
|
||||
}
|
||||
|
||||
gcry_cipher_setiv (cipher_hd, protect_iv, protect_ivlen);
|
||||
|
||||
actual_csum = 0;
|
||||
if (pkt_version >= 4)
|
||||
{
|
||||
int ndata;
|
||||
unsigned int ndatabits;
|
||||
unsigned char *p, *data;
|
||||
u16 csum_pgp7 = 0;
|
||||
|
||||
if (!gcry_mpi_get_flag (skey[npkey], GCRYMPI_FLAG_OPAQUE ))
|
||||
{
|
||||
gcry_cipher_close (cipher_hd);
|
||||
return gpg_error (GPG_ERR_BAD_SECKEY);
|
||||
}
|
||||
p = gcry_mpi_get_opaque (skey[npkey], &ndatabits);
|
||||
ndata = (ndatabits+7)/8;
|
||||
|
||||
if (ndata > 1)
|
||||
csum_pgp7 = p[ndata-2] << 8 | p[ndata-1];
|
||||
data = xtrymalloc_secure (ndata);
|
||||
if (!data)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
gcry_cipher_close (cipher_hd);
|
||||
return err;
|
||||
}
|
||||
gcry_cipher_decrypt (cipher_hd, data, ndata, p, ndata);
|
||||
|
||||
p = data;
|
||||
if (is_protected == 2)
|
||||
{
|
||||
/* This is the new SHA1 checksum method to detect tampering
|
||||
with the key as used by the Klima/Rosa attack. */
|
||||
desired_csum = 0;
|
||||
actual_csum = 1; /* Default to bad checksum. */
|
||||
|
||||
if (ndata < 20)
|
||||
log_error ("not enough bytes for SHA-1 checksum\n");
|
||||
else
|
||||
{
|
||||
gcry_md_hd_t h;
|
||||
|
||||
if (gcry_md_open (&h, GCRY_MD_SHA1, 1))
|
||||
BUG(); /* Algo not available. */
|
||||
gcry_md_write (h, data, ndata - 20);
|
||||
gcry_md_final (h);
|
||||
if (!memcmp (gcry_md_read (h, GCRY_MD_SHA1), data+ndata-20, 20))
|
||||
actual_csum = 0; /* Digest does match. */
|
||||
gcry_md_close (h);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Old 16 bit checksum method. */
|
||||
if (ndata < 2)
|
||||
{
|
||||
log_error ("not enough bytes for checksum\n");
|
||||
desired_csum = 0;
|
||||
actual_csum = 1; /* Mark checksum bad. */
|
||||
}
|
||||
else
|
||||
{
|
||||
desired_csum = (data[ndata-2] << 8 | data[ndata-1]);
|
||||
actual_csum = checksum (data, ndata-2);
|
||||
if (desired_csum != actual_csum)
|
||||
{
|
||||
/* This is a PGP 7.0.0 workaround */
|
||||
desired_csum = csum_pgp7; /* Take the encrypted one. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Better check it here. Otherwise the gcry_mpi_scan would fail
|
||||
because the length may have an arbitrary value. */
|
||||
if (desired_csum == actual_csum)
|
||||
{
|
||||
for (i=npkey; i < nskey; i++ )
|
||||
{
|
||||
if (gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_PGP, p, ndata, &nbytes))
|
||||
{
|
||||
/* Checksum was okay, but not correctly decrypted. */
|
||||
desired_csum = 0;
|
||||
actual_csum = 1; /* Mark checksum bad. */
|
||||
break;
|
||||
}
|
||||
gcry_mpi_release (skey[i]);
|
||||
skey[i] = tmpmpi;
|
||||
ndata -= nbytes;
|
||||
p += nbytes;
|
||||
}
|
||||
skey[i] = NULL;
|
||||
skeylen = i;
|
||||
assert (skeylen <= skeysize);
|
||||
|
||||
/* Note: at this point NDATA should be 2 for a simple
|
||||
checksum or 20 for the sha1 digest. */
|
||||
}
|
||||
xfree(data);
|
||||
}
|
||||
else /* Packet version <= 3. */
|
||||
{
|
||||
unsigned char *buffer;
|
||||
|
||||
for (i = npkey; i < nskey; i++)
|
||||
{
|
||||
unsigned char *p;
|
||||
size_t ndata;
|
||||
unsigned int ndatabits;
|
||||
|
||||
if (!skey[i] || !gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_OPAQUE))
|
||||
{
|
||||
gcry_cipher_close (cipher_hd);
|
||||
return gpg_error (GPG_ERR_BAD_SECKEY);
|
||||
}
|
||||
p = gcry_mpi_get_opaque (skey[i], &ndatabits);
|
||||
ndata = (ndatabits+7)/8;
|
||||
|
||||
if (!(ndata >= 2) || !(ndata == ((p[0] << 8 | p[1]) + 7)/8 + 2))
|
||||
{
|
||||
gcry_cipher_close (cipher_hd);
|
||||
return gpg_error (GPG_ERR_BAD_SECKEY);
|
||||
}
|
||||
|
||||
buffer = xtrymalloc_secure (ndata);
|
||||
if (!buffer)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
gcry_cipher_close (cipher_hd);
|
||||
return err;
|
||||
}
|
||||
|
||||
gcry_cipher_sync (cipher_hd);
|
||||
buffer[0] = p[0];
|
||||
buffer[1] = p[1];
|
||||
gcry_cipher_decrypt (cipher_hd, buffer+2, ndata-2, p+2, ndata-2);
|
||||
actual_csum += checksum (buffer, ndata);
|
||||
err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_PGP, buffer, ndata, &ndata);
|
||||
xfree (buffer);
|
||||
if (err)
|
||||
{
|
||||
/* Checksum was okay, but not correctly decrypted. */
|
||||
desired_csum = 0;
|
||||
actual_csum = 1; /* Mark checksum bad. */
|
||||
break;
|
||||
}
|
||||
gcry_mpi_release (skey[i]);
|
||||
skey[i] = tmpmpi;
|
||||
}
|
||||
}
|
||||
gcry_cipher_close (cipher_hd);
|
||||
|
||||
/* Now let's see whether we have used the correct passphrase. */
|
||||
if (actual_csum != desired_csum)
|
||||
return gpg_error (GPG_ERR_BAD_PASSPHRASE);
|
||||
|
||||
if (nskey != skeylen)
|
||||
err = gpg_error (GPG_ERR_BAD_SECKEY);
|
||||
else
|
||||
err = convert_secret_key (r_key, pubkey_algo, skey);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* The checksum may fail, thus we also check the key itself. */
|
||||
err = gcry_pk_testkey (*r_key);
|
||||
if (err)
|
||||
{
|
||||
gcry_sexp_release (*r_key);
|
||||
*r_key = NULL;
|
||||
return gpg_error (GPG_ERR_BAD_PASSPHRASE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Callback function to try the unprotection from the passpharse query
|
||||
code. */
|
||||
static int
|
||||
try_do_unprotect_cb (struct pin_entry_info_s *pi)
|
||||
{
|
||||
gpg_error_t err;
|
||||
struct try_do_unprotect_arg_s *arg = pi->check_cb_arg;
|
||||
|
||||
err = do_unprotect (pi->pin, arg->is_v4? 4:3,
|
||||
arg->pubkey_algo, arg->is_protected,
|
||||
arg->skey, arg->skeysize,
|
||||
arg->protect_algo, arg->iv, arg->ivlen,
|
||||
arg->s2k_mode, arg->s2k_algo,
|
||||
arg->s2k_salt, arg->s2k_count,
|
||||
arg->desired_csum, arg->r_key);
|
||||
/* SKEY may be modified now, thus we need to re-compute SKEYIDX. */
|
||||
for (arg->skeyidx = 0; (arg->skeyidx < arg->skeysize
|
||||
&& arg->skey[arg->skeyidx]); arg->skeyidx++)
|
||||
;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Convert an OpenPGP transfer key into our internal format. Before
|
||||
asking for a passphrase we check whether the key already exists in
|
||||
our key storage. S_PGP is the OpenPGP key in transfer format. On
|
||||
success R_KEY will receive a canonical encoded S-expression with
|
||||
the unprotected key in our internal format; the caller needs to
|
||||
release that memory. The passphrase used to decrypt the OpenPGP
|
||||
key will be returned at R_PASSPHRASE; the caller must release this
|
||||
passphrase. The keygrip will be stored at the 20 byte buffer
|
||||
pointed to by GRIP. On error NULL is stored at all return
|
||||
arguments. */
|
||||
gpg_error_t
|
||||
convert_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp,
|
||||
unsigned char *grip, const char *prompt,
|
||||
unsigned char **r_key, char **r_passphrase)
|
||||
{
|
||||
gpg_error_t err;
|
||||
gcry_sexp_t top_list;
|
||||
gcry_sexp_t list = NULL;
|
||||
const char *value;
|
||||
size_t valuelen;
|
||||
char *string;
|
||||
int idx;
|
||||
int is_v4, is_protected;
|
||||
int pubkey_algo;
|
||||
int protect_algo = 0;
|
||||
char iv[16];
|
||||
int ivlen = 0;
|
||||
int s2k_mode = 0;
|
||||
int s2k_algo = 0;
|
||||
byte s2k_salt[8];
|
||||
u32 s2k_count = 0;
|
||||
size_t npkey, nskey;
|
||||
gcry_mpi_t skey[10]; /* We support up to 9 parameters. */
|
||||
u16 desired_csum;
|
||||
int skeyidx = 0;
|
||||
gcry_sexp_t s_skey;
|
||||
struct pin_entry_info_s *pi;
|
||||
struct try_do_unprotect_arg_s pi_arg;
|
||||
|
||||
*r_key = NULL;
|
||||
*r_passphrase = NULL;
|
||||
|
||||
top_list = gcry_sexp_find_token (s_pgp, "openpgp-private-key", 0);
|
||||
if (!top_list)
|
||||
goto bad_seckey;
|
||||
|
||||
list = gcry_sexp_find_token (top_list, "version", 0);
|
||||
if (!list)
|
||||
goto bad_seckey;
|
||||
value = gcry_sexp_nth_data (list, 1, &valuelen);
|
||||
if (!value || valuelen != 1 || !(value[0] == '3' || value[0] == '4'))
|
||||
goto bad_seckey;
|
||||
is_v4 = (value[0] == '4');
|
||||
|
||||
gcry_sexp_release (list);
|
||||
list = gcry_sexp_find_token (top_list, "protection", 0);
|
||||
if (!list)
|
||||
goto bad_seckey;
|
||||
value = gcry_sexp_nth_data (list, 1, &valuelen);
|
||||
if (!value)
|
||||
goto bad_seckey;
|
||||
if (valuelen == 4 && !memcmp (value, "sha1", 4))
|
||||
is_protected = 2;
|
||||
else if (valuelen == 3 && !memcmp (value, "sum", 3))
|
||||
is_protected = 1;
|
||||
else if (valuelen == 4 && !memcmp (value, "none", 4))
|
||||
is_protected = 0;
|
||||
else
|
||||
goto bad_seckey;
|
||||
if (is_protected)
|
||||
{
|
||||
string = gcry_sexp_nth_string (list, 2);
|
||||
if (!string)
|
||||
goto bad_seckey;
|
||||
protect_algo = gcry_cipher_map_name (string);
|
||||
if (!protect_algo && !!strcmp (string, "IDEA"))
|
||||
protect_algo = GCRY_CIPHER_IDEA;
|
||||
xfree (string);
|
||||
|
||||
value = gcry_sexp_nth_data (list, 3, &valuelen);
|
||||
if (!value || !valuelen || valuelen > sizeof iv)
|
||||
goto bad_seckey;
|
||||
memcpy (iv, value, valuelen);
|
||||
ivlen = valuelen;
|
||||
|
||||
string = gcry_sexp_nth_string (list, 4);
|
||||
if (!string)
|
||||
goto bad_seckey;
|
||||
s2k_mode = strtol (string, NULL, 10);
|
||||
xfree (string);
|
||||
|
||||
string = gcry_sexp_nth_string (list, 5);
|
||||
if (!string)
|
||||
goto bad_seckey;
|
||||
s2k_algo = gcry_md_map_name (string);
|
||||
xfree (string);
|
||||
|
||||
value = gcry_sexp_nth_data (list, 6, &valuelen);
|
||||
if (!value || !valuelen || valuelen > sizeof s2k_salt)
|
||||
goto bad_seckey;
|
||||
memcpy (s2k_salt, value, valuelen);
|
||||
|
||||
string = gcry_sexp_nth_string (list, 7);
|
||||
if (!string)
|
||||
goto bad_seckey;
|
||||
s2k_count = strtoul (string, NULL, 10);
|
||||
xfree (string);
|
||||
}
|
||||
|
||||
gcry_sexp_release (list);
|
||||
list = gcry_sexp_find_token (top_list, "algo", 0);
|
||||
if (!list)
|
||||
goto bad_seckey;
|
||||
string = gcry_sexp_nth_string (list, 1);
|
||||
if (!string)
|
||||
goto bad_seckey;
|
||||
pubkey_algo = gcry_pk_map_name (string);
|
||||
xfree (string);
|
||||
|
||||
if (gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &npkey)
|
||||
|| gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &nskey)
|
||||
|| !npkey || npkey >= nskey)
|
||||
goto bad_seckey;
|
||||
|
||||
gcry_sexp_release (list);
|
||||
list = gcry_sexp_find_token (top_list, "skey", 0);
|
||||
if (!list)
|
||||
goto bad_seckey;
|
||||
for (idx=0;;)
|
||||
{
|
||||
int is_enc;
|
||||
|
||||
value = gcry_sexp_nth_data (list, ++idx, &valuelen);
|
||||
if (!value && skeyidx >= npkey)
|
||||
break; /* Ready. */
|
||||
|
||||
/* Check for too many parameters. Note that depending on the
|
||||
protection mode and version number we may see less than NSKEY
|
||||
(but at least NPKEY+1) parameters. */
|
||||
if (idx >= 2*nskey)
|
||||
goto bad_seckey;
|
||||
if (skeyidx >= DIM (skey)-1)
|
||||
goto bad_seckey;
|
||||
|
||||
if (!value || valuelen != 1 || !(value[0] == '_' || value[0] == 'e'))
|
||||
goto bad_seckey;
|
||||
is_enc = (value[0] == 'e');
|
||||
value = gcry_sexp_nth_data (list, ++idx, &valuelen);
|
||||
if (!value || !valuelen)
|
||||
goto bad_seckey;
|
||||
if (is_enc)
|
||||
{
|
||||
void *p = xtrymalloc (valuelen);
|
||||
if (!p)
|
||||
goto outofmem;
|
||||
memcpy (p, value, valuelen);
|
||||
skey[skeyidx] = gcry_mpi_set_opaque (NULL, p, valuelen*8);
|
||||
if (!skey[skeyidx])
|
||||
goto outofmem;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gcry_mpi_scan (skey + skeyidx, GCRYMPI_FMT_STD,
|
||||
value, valuelen, NULL))
|
||||
goto bad_seckey;
|
||||
}
|
||||
skeyidx++;
|
||||
}
|
||||
skey[skeyidx++] = NULL;
|
||||
|
||||
gcry_sexp_release (list);
|
||||
list = gcry_sexp_find_token (top_list, "csum", 0);
|
||||
if (list)
|
||||
{
|
||||
string = gcry_sexp_nth_string (list, 1);
|
||||
if (!string)
|
||||
goto bad_seckey;
|
||||
desired_csum = strtoul (string, NULL, 10);
|
||||
xfree (string);
|
||||
}
|
||||
else
|
||||
desired_csum = 0;
|
||||
|
||||
|
||||
gcry_sexp_release (list); list = NULL;
|
||||
gcry_sexp_release (top_list); top_list = NULL;
|
||||
|
||||
/* log_debug ("XXX is_v4=%d\n", is_v4); */
|
||||
/* log_debug ("XXX pubkey_algo=%d\n", pubkey_algo); */
|
||||
/* log_debug ("XXX is_protected=%d\n", is_protected); */
|
||||
/* log_debug ("XXX protect_algo=%d\n", protect_algo); */
|
||||
/* log_printhex ("XXX iv", iv, ivlen); */
|
||||
/* log_debug ("XXX ivlen=%d\n", ivlen); */
|
||||
/* log_debug ("XXX s2k_mode=%d\n", s2k_mode); */
|
||||
/* log_debug ("XXX s2k_algo=%d\n", s2k_algo); */
|
||||
/* log_printhex ("XXX s2k_salt", s2k_salt, sizeof s2k_salt); */
|
||||
/* log_debug ("XXX s2k_count=%lu\n", (unsigned long)s2k_count); */
|
||||
/* for (idx=0; skey[idx]; idx++) */
|
||||
/* { */
|
||||
/* int is_enc = gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_OPAQUE); */
|
||||
/* log_info ("XXX skey[%d]%s:", idx, is_enc? " (enc)":""); */
|
||||
/* if (is_enc) */
|
||||
/* { */
|
||||
/* void *p; */
|
||||
/* unsigned int nbits; */
|
||||
/* p = gcry_mpi_get_opaque (skey[idx], &nbits); */
|
||||
/* log_printhex (NULL, p, (nbits+7)/8); */
|
||||
/* } */
|
||||
/* else */
|
||||
/* gcry_mpi_dump (skey[idx]); */
|
||||
/* log_printf ("\n"); */
|
||||
/* } */
|
||||
|
||||
err = get_keygrip (pubkey_algo, skey, grip);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
if (!agent_key_available (grip))
|
||||
{
|
||||
err = gpg_error (GPG_ERR_EEXIST);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
pi = xtrycalloc_secure (1, sizeof (*pi) + 100);
|
||||
if (!pi)
|
||||
return gpg_error_from_syserror ();
|
||||
pi->max_length = 100;
|
||||
pi->min_digits = 0; /* We want a real passphrase. */
|
||||
pi->max_digits = 16;
|
||||
pi->max_tries = 3;
|
||||
pi->check_cb = try_do_unprotect_cb;
|
||||
pi->check_cb_arg = &pi_arg;
|
||||
pi_arg.is_v4 = is_v4;
|
||||
pi_arg.is_protected = is_protected;
|
||||
pi_arg.pubkey_algo = pubkey_algo;
|
||||
pi_arg.protect_algo = protect_algo;
|
||||
pi_arg.iv = iv;
|
||||
pi_arg.ivlen = ivlen;
|
||||
pi_arg.s2k_mode = s2k_mode;
|
||||
pi_arg.s2k_algo = s2k_algo;
|
||||
pi_arg.s2k_salt = s2k_salt;
|
||||
pi_arg.s2k_count = s2k_count;
|
||||
pi_arg.desired_csum = desired_csum;
|
||||
pi_arg.skey = skey;
|
||||
pi_arg.skeysize = DIM (skey);
|
||||
pi_arg.skeyidx = skeyidx;
|
||||
pi_arg.r_key = &s_skey;
|
||||
err = agent_askpin (ctrl, prompt, NULL, NULL, pi);
|
||||
skeyidx = pi_arg.skeyidx;
|
||||
if (!err)
|
||||
{
|
||||
*r_passphrase = xtrystrdup (pi->pin);
|
||||
if (!*r_passphrase)
|
||||
err = gpg_error_from_syserror ();
|
||||
}
|
||||
xfree (pi);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
/* Save some memory and get rid of the SKEY array now. */
|
||||
for (idx=0; idx < skeyidx; idx++)
|
||||
gcry_mpi_release (skey[idx]);
|
||||
skeyidx = 0;
|
||||
|
||||
/* Note that the padding is not required - we use it only because
|
||||
that function allows us to created the result in secure memory. */
|
||||
err = make_canon_sexp_pad (s_skey, 1, r_key, NULL);
|
||||
gcry_sexp_release (s_skey);
|
||||
|
||||
leave:
|
||||
gcry_sexp_release (list);
|
||||
gcry_sexp_release (top_list);
|
||||
for (idx=0; idx < skeyidx; idx++)
|
||||
gcry_mpi_release (skey[idx]);
|
||||
if (err)
|
||||
{
|
||||
xfree (*r_passphrase);
|
||||
*r_passphrase = NULL;
|
||||
}
|
||||
return err;
|
||||
|
||||
bad_seckey:
|
||||
err = gpg_error (GPG_ERR_BAD_SECKEY);
|
||||
goto leave;
|
||||
|
||||
outofmem:
|
||||
err = gpg_error (GPG_ERR_ENOMEM);
|
||||
goto leave;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
27
agent/cvt-openpgp.h
Normal file
27
agent/cvt-openpgp.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/* cvt-openpgp.h - Convert an OpenPGP key to our internal format.
|
||||
* Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef GNUPG_AGENT_CVT_OPENPGP_H
|
||||
#define GNUPG_AGENT_CVT_OPENPGP_H
|
||||
|
||||
gpg_error_t convert_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp,
|
||||
unsigned char *grip, const char *prompt,
|
||||
unsigned char **r_key, char **r_passphrase);
|
||||
|
||||
|
||||
#endif /*GNUPG_AGENT_CVT_OPENPGP_H*/
|
|
@ -702,7 +702,8 @@ key_parms_from_sexp (gcry_sexp_t s_key, gcry_sexp_t *r_list,
|
|||
}
|
||||
|
||||
|
||||
/* Return true if S_KEY is a DSA style key. */
|
||||
/* Return the public key algorithm number if S_KEY is a DSA style key.
|
||||
If it is not a DSA style key, return 0. */
|
||||
int
|
||||
agent_is_dsa_key (gcry_sexp_t s_key)
|
||||
{
|
||||
|
@ -714,7 +715,12 @@ agent_is_dsa_key (gcry_sexp_t s_key)
|
|||
if (key_parms_from_sexp (s_key, NULL, algoname, sizeof algoname, NULL, 0))
|
||||
return 0; /* Error - assume it is not an DSA key. */
|
||||
|
||||
return (!strcmp (algoname, "dsa") || !strcmp (algoname, "ecdsa"));
|
||||
if (!strcmp (algoname, "dsa"))
|
||||
return GCRY_PK_DSA;
|
||||
else if (!strcmp (algoname, "ecdsa"))
|
||||
return GCRY_PK_ECDSA;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -159,7 +159,34 @@ second list with the information has this layout:
|
|||
More items may be added to the list.
|
||||
|
||||
|
||||
OpenPGP Private Key Transfer Format
|
||||
===================================
|
||||
|
||||
This format is used to transfer keys between gpg and gpg-agent.
|
||||
|
||||
(openpgp-private-key
|
||||
(version V)
|
||||
(protection PROTTYPE PROTALGO IV S2KMODE S2KHASH S2KSALT S2KCOUNT)
|
||||
(algo PUBKEYALGO)
|
||||
(skey CSUM c P1 c P2 c P3 ... e PN))
|
||||
|
||||
|
||||
* V is the packet version number (3 or 4).
|
||||
* PUBKEYALGO is a Libgcrypt algo name
|
||||
* CSUM is the 16 bit checksum as defined by OpenPGP.
|
||||
* P1 .. PN are the parameters; the public parameters are never encrypted
|
||||
the secrect key parameters are encrypted if the "protection" list is
|
||||
given. To make this more explicit each parameter is preceded by a
|
||||
flag "_" for cleartext or "e" for encrypted text.
|
||||
* If PROTTYPE is "sha1" the new style SHA1 checksum is used if it is "sum"
|
||||
the old 16 bit checksum is used and if it is "none" no protection at
|
||||
all is used.
|
||||
* PROTALGO is a Libgcrypt style cipher algorithm name
|
||||
* IV is the initialization verctor.
|
||||
* S2KMODE is the value from RFC-4880.
|
||||
* S2KHASH is a a libgcrypt style hash algorithm identifier.
|
||||
* S2KSALT is the 8 byte salt
|
||||
* S2KCOUNT is the count value from RFC-4880.
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -164,10 +164,22 @@ do_encode_dsa (const byte * md, size_t mdlen, int dsaalgo, gcry_sexp_t pkey,
|
|||
if (mdlen > qbits/8)
|
||||
mdlen = qbits/8;
|
||||
|
||||
/* Create the S-expression. */
|
||||
err = gcry_sexp_build (&hash, NULL,
|
||||
"(data (flags raw) (value %b))",
|
||||
(int)mdlen, md);
|
||||
/* Create the S-expression. We need to convert to an MPI first
|
||||
because we want an unsigned integer. Using %b directly is not
|
||||
possible because libgcrypt assumes an mpi and uses
|
||||
GCRYMPI_FMT_STD for parsing and thus possible yielding a negative
|
||||
value. */
|
||||
{
|
||||
gcry_mpi_t mpi;
|
||||
|
||||
err = gcry_mpi_scan (&mpi, GCRYMPI_FMT_USG, md, mdlen, NULL);
|
||||
if (!err)
|
||||
{
|
||||
err = gcry_sexp_build (&hash, NULL,
|
||||
"(data (flags raw) (value %m))", mpi);
|
||||
gcry_mpi_release (mpi);
|
||||
}
|
||||
}
|
||||
if (!err)
|
||||
*r_hash = hash;
|
||||
return err;
|
||||
|
@ -304,8 +316,10 @@ agent_pksign_do (ctrl_t ctrl, const char *desc_text,
|
|||
|
||||
if (DBG_CRYPTO)
|
||||
{
|
||||
log_debug ("skey: ");
|
||||
log_debug ("skey:\n");
|
||||
gcry_sexp_dump (s_skey);
|
||||
log_debug ("hash:\n");
|
||||
gcry_sexp_dump (s_hash);
|
||||
}
|
||||
|
||||
/* sign */
|
||||
|
@ -319,7 +333,7 @@ agent_pksign_do (ctrl_t ctrl, const char *desc_text,
|
|||
|
||||
if (DBG_CRYPTO)
|
||||
{
|
||||
log_debug ("result: ");
|
||||
log_debug ("result:\n");
|
||||
gcry_sexp_dump (s_sig);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,6 +73,8 @@ hash_passphrase (const char *passphrase, int hashalgo,
|
|||
const unsigned char *s2ksalt, unsigned long s2kcount,
|
||||
unsigned char *key, size_t keylen);
|
||||
|
||||
|
||||
|
||||
/* Get the process time and store it in DATA. */
|
||||
static void
|
||||
calibrate_get_time (struct calibrate_time_s *data)
|
||||
|
@ -1076,6 +1078,19 @@ hash_passphrase (const char *passphrase, int hashalgo,
|
|||
}
|
||||
|
||||
|
||||
gpg_error_t
|
||||
s2k_hash_passphrase (const char *passphrase, int hashalgo,
|
||||
int s2kmode,
|
||||
const unsigned char *s2ksalt,
|
||||
unsigned int s2kcount,
|
||||
unsigned char *key, size_t keylen)
|
||||
{
|
||||
return hash_passphrase (passphrase, hashalgo, s2kmode, s2ksalt,
|
||||
(16ul + (s2kcount & 15)) << ((s2kcount >> 4) + 6),
|
||||
key, keylen);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Create an canonical encoded S-expression with the shadow info from
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue