mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
agent: Cleanups to prepare implementation of Ed25519.
* agent/cvt-openpgp.c: Remove. (convert_to_openpgp): Use gcry_sexp_extract_param. * agent/findkey.c (is_eddsa): New. (agent_is_dsa_key, agent_is_eddsa_key): Check whether ecc means EdDSA. * agent/pksign.c (agent_pksign_do): Add args OVERRIDEDATA and OVERRIDEDATALEN. * common/ssh-utils.c (is_eddsa): New. (get_fingerprint): Take care or EdDSA.
This commit is contained in:
parent
6376227a31
commit
a77ed0f266
@ -368,7 +368,8 @@ char *agent_get_cache (const char *key, cache_mode_t cache_mode);
|
||||
int agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
|
||||
const char *desc_text,
|
||||
gcry_sexp_t *signature_sexp,
|
||||
cache_mode_t cache_mode, lookup_ttl_t lookup_ttl);
|
||||
cache_mode_t cache_mode, lookup_ttl_t lookup_ttl,
|
||||
const void *overridedata, size_t overridedatalen);
|
||||
int agent_pksign (ctrl_t ctrl, const char *cache_nonce,
|
||||
const char *desc_text,
|
||||
membuf_t *outbuf, cache_mode_t cache_mode);
|
||||
|
@ -2515,7 +2515,8 @@ data_sign (ctrl_t ctrl, ssh_key_type_spec_t *spec,
|
||||
_("Please enter the passphrase "
|
||||
"for the ssh key%%0A %F%%0A (%c)"),
|
||||
&signature_sexp,
|
||||
CACHE_MODE_SSH, ttl_from_sshcontrol);
|
||||
CACHE_MODE_SSH, ttl_from_sshcontrol,
|
||||
NULL, 0);
|
||||
ctrl->use_auth_call = 0;
|
||||
if (err)
|
||||
goto out;
|
||||
|
@ -2147,7 +2147,7 @@ cmd_export_key (assuan_context_t ctx, char *line)
|
||||
|
||||
if (!ctrl->server_local->export_key)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_MISSING_KEY);
|
||||
err = set_error (GPG_ERR_MISSING_KEY, "did you run KEYWRAP_KEY");
|
||||
goto leave;
|
||||
}
|
||||
|
||||
|
@ -1030,46 +1030,6 @@ convert_from_openpgp_native (ctrl_t ctrl,
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
key_from_sexp (gcry_sexp_t sexp, const char *elems, gcry_mpi_t *array)
|
||||
{
|
||||
gpg_error_t err = 0;
|
||||
gcry_sexp_t l2;
|
||||
int idx;
|
||||
|
||||
for (idx=0; *elems; elems++, idx++)
|
||||
{
|
||||
l2 = gcry_sexp_find_token (sexp, elems, 1);
|
||||
if (!l2)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_NO_OBJ); /* Required parameter not found. */
|
||||
goto leave;
|
||||
}
|
||||
array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
|
||||
gcry_sexp_release (l2);
|
||||
if (!array[idx])
|
||||
{
|
||||
err = gpg_error (GPG_ERR_INV_OBJ); /* Required parameter invalid. */
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
leave:
|
||||
if (err)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < idx; i++)
|
||||
{
|
||||
gcry_mpi_release (array[i]);
|
||||
array[i] = NULL;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Given an ARRAY of mpis with the key parameters, protect the secret
|
||||
parameters in that array and replace them by one opaque encoded
|
||||
mpi. NPKEY is the number of public key parameters and NSKEY is
|
||||
@ -1173,7 +1133,6 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
|
||||
gpg_error_t err;
|
||||
gcry_sexp_t list, l2;
|
||||
char *name;
|
||||
int algo;
|
||||
const char *algoname;
|
||||
const char *elems;
|
||||
int npkey, nskey;
|
||||
@ -1203,26 +1162,63 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
|
||||
return gpg_error (GPG_ERR_INV_OBJ); /* Invalid structure of object. */
|
||||
}
|
||||
|
||||
algo = gcry_pk_map_name (name);
|
||||
xfree (name);
|
||||
|
||||
switch (algo)
|
||||
/* Map NAME to a name as used by Libgcrypt. We do not use the
|
||||
Libgcrypt function here because we need a lowercase name and
|
||||
require special treatment for some algorithms. */
|
||||
strlwr (name);
|
||||
if (!strcmp (name, "rsa"))
|
||||
{
|
||||
case GCRY_PK_RSA: algoname = "rsa"; npkey = 2; elems = "nedpqu"; break;
|
||||
case GCRY_PK_ELG: algoname = "elg"; npkey = 3; elems = "pgyx"; break;
|
||||
case GCRY_PK_ELG_E: algoname = "elg"; npkey = 3; elems = "pgyx"; break;
|
||||
case GCRY_PK_DSA: algoname = "dsa"; npkey = 4; elems = "pqgyx"; break;
|
||||
case GCRY_PK_ECDSA: algoname = "ecdsa"; npkey = 6; elems = "pabgnqd"; break;
|
||||
case GCRY_PK_ECDH: algoname = "ecdh"; npkey = 6; elems = "pabgnqd"; break;
|
||||
default: algoname = ""; npkey = 0; elems = NULL; break;
|
||||
algoname = "rsa";
|
||||
npkey = 2;
|
||||
elems = "nedpqu";
|
||||
}
|
||||
else if (!strcmp (name, "elg"))
|
||||
{
|
||||
algoname = "elg";
|
||||
npkey = 3;
|
||||
elems = "pgyx";
|
||||
}
|
||||
else if (!strcmp (name, "dsa"))
|
||||
{
|
||||
algoname = "dsa";
|
||||
npkey = 4;
|
||||
elems = "pqgyx";
|
||||
}
|
||||
else if (!strcmp (name, "ecc"))
|
||||
{
|
||||
algoname = "?"; /* Decide later by checking the usage. */
|
||||
npkey = 6;
|
||||
elems = "pabgnqd";
|
||||
}
|
||||
else if (!strcmp (name, "ecdsa"))
|
||||
{
|
||||
algoname = "ecdsa";
|
||||
npkey = 6;
|
||||
elems = "pabgnqd";
|
||||
}
|
||||
else if (!strcmp (name, "ecdh"))
|
||||
{
|
||||
algoname = "ecdh";
|
||||
npkey = 6;
|
||||
elems = "pabgnqd";
|
||||
}
|
||||
else
|
||||
{
|
||||
algoname = "";
|
||||
npkey = 0;
|
||||
elems = NULL;
|
||||
}
|
||||
xfree (name);
|
||||
assert (!elems || strlen (elems) < DIM (array) );
|
||||
nskey = elems? strlen (elems) : 0;
|
||||
|
||||
/* Extract the parameters and put them into an array. */
|
||||
if (!elems)
|
||||
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
else
|
||||
err = key_from_sexp (list, elems, array);
|
||||
err = gcry_sexp_extract_param (list, NULL, elems,
|
||||
array+0, array+1, array+2, array+3, array+4,
|
||||
array+5, array+6, NULL);
|
||||
gcry_sexp_release (list);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -688,7 +688,7 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
|
||||
string describing the names of the parameters. ALGONAMESIZE and
|
||||
ELEMSSIZE give the allocated size of the provided buffers. The
|
||||
buffers may be NULL if not required. If R_LIST is not NULL the top
|
||||
level list will be stored tehre; the caller needs to release it in
|
||||
level list will be stored there; the caller needs to release it in
|
||||
this case. */
|
||||
static gpg_error_t
|
||||
key_parms_from_sexp (gcry_sexp_t s_key, gcry_sexp_t *r_list,
|
||||
@ -776,27 +776,65 @@ key_parms_from_sexp (gcry_sexp_t s_key, gcry_sexp_t *r_list,
|
||||
}
|
||||
|
||||
|
||||
/* Return true if KEYPARMS holds an EdDSA key. */
|
||||
static int
|
||||
is_eddsa (gcry_sexp_t keyparms)
|
||||
{
|
||||
int result = 0;
|
||||
gcry_sexp_t list;
|
||||
const char *s;
|
||||
size_t n;
|
||||
int i;
|
||||
|
||||
list = gcry_sexp_find_token (keyparms, "flags", 0);
|
||||
for (i = list ? gcry_sexp_length (list)-1 : 0; i > 0; i--)
|
||||
{
|
||||
s = gcry_sexp_nth_data (list, i, &n);
|
||||
if (!s)
|
||||
continue; /* Not a data element. */
|
||||
|
||||
if (n == 5 && !memcmp (s, "eddsa", 5))
|
||||
{
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
gcry_sexp_release (list);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* 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)
|
||||
{
|
||||
int result;
|
||||
gcry_sexp_t list;
|
||||
char algoname[6];
|
||||
|
||||
if (!s_key)
|
||||
return 0;
|
||||
|
||||
if (key_parms_from_sexp (s_key, NULL, algoname, sizeof algoname, NULL, 0))
|
||||
if (key_parms_from_sexp (s_key, &list, algoname, sizeof algoname, NULL, 0))
|
||||
return 0; /* Error - assume it is not an DSA key. */
|
||||
|
||||
if (!strcmp (algoname, "dsa"))
|
||||
return GCRY_PK_DSA;
|
||||
result = GCRY_PK_DSA;
|
||||
else if (!strcmp (algoname, "ecc"))
|
||||
return GCRY_PK_ECDSA; /* FIXME: Check for the EdDSA flag. */
|
||||
{
|
||||
if (is_eddsa (list))
|
||||
result = 0;
|
||||
else
|
||||
result = GCRY_PK_ECDSA;
|
||||
}
|
||||
else if (!strcmp (algoname, "ecdsa"))
|
||||
return GCRY_PK_ECDSA;
|
||||
result = GCRY_PK_ECDSA;
|
||||
else
|
||||
return 0;
|
||||
result = 0;
|
||||
|
||||
gcry_sexp_release (list);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -804,18 +842,25 @@ agent_is_dsa_key (gcry_sexp_t s_key)
|
||||
int
|
||||
agent_is_eddsa_key (gcry_sexp_t s_key)
|
||||
{
|
||||
int result;
|
||||
gcry_sexp_t list;
|
||||
char algoname[6];
|
||||
|
||||
if (!s_key)
|
||||
return 0;
|
||||
|
||||
if (key_parms_from_sexp (s_key, NULL, algoname, sizeof algoname, NULL, 0))
|
||||
if (key_parms_from_sexp (s_key, &list, algoname, sizeof algoname, NULL, 0))
|
||||
return 0; /* Error - assume it is not an EdDSA key. */
|
||||
|
||||
if (!strcmp (algoname, "eddsa"))
|
||||
return 1;
|
||||
if (!strcmp (algoname, "ecc") && is_eddsa (list))
|
||||
result = 1;
|
||||
else if (!strcmp (algoname, "eddsa")) /* backward compatibility. */
|
||||
result = 1;
|
||||
else
|
||||
return 0;
|
||||
result = 0;
|
||||
|
||||
gcry_sexp_release (list);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -276,18 +276,35 @@ do_encode_raw_pkcs1 (const byte *md, size_t mdlen, unsigned int nbits,
|
||||
the signature S-expression. LOOKUP is an optional function to
|
||||
provide a way for lower layers to ask for the caching TTL. If a
|
||||
CACHE_NONCE is given that cache item is first tried to get a
|
||||
passphrase. */
|
||||
passphrase. If OVERRIDEDATA is not NULL, OVERRIDEDATALEN bytes
|
||||
from this buffer are used instead of the data in CTRL. The
|
||||
override feature is required to allow the use of Ed25519 with ssh
|
||||
because Ed25519 dies the hashing itself. */
|
||||
int
|
||||
agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
|
||||
const char *desc_text,
|
||||
gcry_sexp_t *signature_sexp,
|
||||
cache_mode_t cache_mode, lookup_ttl_t lookup_ttl)
|
||||
cache_mode_t cache_mode, lookup_ttl_t lookup_ttl,
|
||||
const void *overridedata, size_t overridedatalen)
|
||||
{
|
||||
gcry_sexp_t s_skey = NULL, s_sig = NULL;
|
||||
unsigned char *shadow_info = NULL;
|
||||
unsigned int rc = 0; /* FIXME: gpg-error? */
|
||||
const unsigned char *data;
|
||||
int datalen;
|
||||
|
||||
if (! ctrl->have_keygrip)
|
||||
if (overridedata)
|
||||
{
|
||||
data = overridedata;
|
||||
datalen = overridedatalen;
|
||||
}
|
||||
else
|
||||
{
|
||||
data = ctrl->digest.value;
|
||||
datalen = ctrl->digest.valuelen;
|
||||
}
|
||||
|
||||
if (!ctrl->have_keygrip)
|
||||
return gpg_error (GPG_ERR_NO_SECKEY);
|
||||
|
||||
rc = agent_key_from_file (ctrl, cache_nonce, desc_text, ctrl->keygrip,
|
||||
@ -315,8 +332,7 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
|
||||
is_ECDSA = 1;
|
||||
|
||||
rc = divert_pksign (ctrl,
|
||||
ctrl->digest.value,
|
||||
ctrl->digest.valuelen,
|
||||
data, datalen,
|
||||
ctrl->digest.algo,
|
||||
shadow_info, &buf, &len);
|
||||
if (rc)
|
||||
@ -405,22 +421,18 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
|
||||
|
||||
/* Put the hash into a sexp */
|
||||
if (agent_is_eddsa_key (s_skey))
|
||||
rc = do_encode_eddsa (ctrl->digest.value,
|
||||
ctrl->digest.valuelen,
|
||||
rc = do_encode_eddsa (data, datalen,
|
||||
&s_hash);
|
||||
else if (ctrl->digest.algo == MD_USER_TLS_MD5SHA1)
|
||||
rc = do_encode_raw_pkcs1 (ctrl->digest.value,
|
||||
ctrl->digest.valuelen,
|
||||
rc = do_encode_raw_pkcs1 (data, datalen,
|
||||
gcry_pk_get_nbits (s_skey),
|
||||
&s_hash);
|
||||
else if ( (dsaalgo = agent_is_dsa_key (s_skey)) )
|
||||
rc = do_encode_dsa (ctrl->digest.value,
|
||||
ctrl->digest.valuelen,
|
||||
rc = do_encode_dsa (data, datalen,
|
||||
dsaalgo, s_skey,
|
||||
&s_hash);
|
||||
else
|
||||
rc = do_encode_md (ctrl->digest.value,
|
||||
ctrl->digest.valuelen,
|
||||
rc = do_encode_md (data, datalen,
|
||||
ctrl->digest.algo,
|
||||
&s_hash,
|
||||
ctrl->digest.raw_value);
|
||||
@ -468,7 +480,8 @@ agent_pksign (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
|
||||
size_t len = 0;
|
||||
int rc = 0;
|
||||
|
||||
rc = agent_pksign_do (ctrl, cache_nonce, desc_text, &s_sig, cache_mode, NULL);
|
||||
rc = agent_pksign_do (ctrl, cache_nonce, desc_text, &s_sig, cache_mode, NULL,
|
||||
NULL, 0);
|
||||
if (rc)
|
||||
goto leave;
|
||||
|
||||
|
@ -37,6 +37,33 @@
|
||||
#include "ssh-utils.h"
|
||||
|
||||
|
||||
/* Return true if KEYPARMS holds an EdDSA key. */
|
||||
static int
|
||||
is_eddsa (gcry_sexp_t keyparms)
|
||||
{
|
||||
int result = 0;
|
||||
gcry_sexp_t list;
|
||||
const char *s;
|
||||
size_t n;
|
||||
int i;
|
||||
|
||||
list = gcry_sexp_find_token (keyparms, "flags", 0);
|
||||
for (i = list ? gcry_sexp_length (list)-1 : 0; i > 0; i--)
|
||||
{
|
||||
s = gcry_sexp_nth_data (list, i, &n);
|
||||
if (!s)
|
||||
continue; /* Not a data element. */
|
||||
|
||||
if (n == 5 && !memcmp (s, "eddsa", 5))
|
||||
{
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
gcry_sexp_release (list);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Return the Secure Shell type fingerprint for KEY. The length of
|
||||
the fingerprint is returned at R_LEN and the fingerprint itself at
|
||||
@ -53,6 +80,7 @@ get_fingerprint (gcry_sexp_t key, void **r_fpr, size_t *r_len, int as_string)
|
||||
int idx;
|
||||
const char *elems;
|
||||
gcry_md_hd_t md = NULL;
|
||||
int blobmode = 0;
|
||||
|
||||
*r_fpr = NULL;
|
||||
*r_len = 0;
|
||||
@ -93,38 +121,52 @@ get_fingerprint (gcry_sexp_t key, void **r_fpr, size_t *r_len, int as_string)
|
||||
elems = "en";
|
||||
gcry_md_write (md, "\0\0\0\x07ssh-rsa", 11);
|
||||
break;
|
||||
|
||||
case GCRY_PK_DSA:
|
||||
elems = "pqgy";
|
||||
gcry_md_write (md, "\0\0\0\x07ssh-dss", 11);
|
||||
break;
|
||||
case GCRY_PK_ECDSA:
|
||||
/* We only support the 3 standard curves for now. It is just a
|
||||
quick hack. */
|
||||
elems = "q";
|
||||
gcry_md_write (md, "\0\0\0\x13" "ecdsa-sha2-nistp", 20);
|
||||
l2 = gcry_sexp_find_token (list, "curve", 0);
|
||||
if (!l2)
|
||||
elems = "";
|
||||
|
||||
case GCRY_PK_ECC:
|
||||
if (is_eddsa (list))
|
||||
{
|
||||
elems = "q";
|
||||
blobmode = 1;
|
||||
/* For now there is just one curve, thus no need to switch
|
||||
on it. */
|
||||
gcry_md_write (md, "\0\0\0\x0b" "ssh-ed25519", 15);
|
||||
}
|
||||
else
|
||||
{
|
||||
gcry_free (name);
|
||||
name = gcry_sexp_nth_string (l2, 1);
|
||||
gcry_sexp_release (l2);
|
||||
l2 = NULL;
|
||||
if (!name)
|
||||
/* We only support the 3 standard curves for now. It is
|
||||
just a quick hack. */
|
||||
elems = "q";
|
||||
gcry_md_write (md, "\0\0\0\x13" "ecdsa-sha2-nistp", 20);
|
||||
l2 = gcry_sexp_find_token (list, "curve", 0);
|
||||
if (!l2)
|
||||
elems = "";
|
||||
else if (!strcmp (name, "NIST P-256") || !strcmp (name, "nistp256"))
|
||||
gcry_md_write (md, "256\0\0\0\x08nistp256", 15);
|
||||
else if (!strcmp (name, "NIST P-384") || !strcmp (name, "nistp384"))
|
||||
gcry_md_write (md, "384\0\0\0\x08nistp521", 15);
|
||||
else if (!strcmp (name, "NIST P-521") || !strcmp (name, "nistp521"))
|
||||
gcry_md_write (md, "521\0\0\0\x08nistp521", 15);
|
||||
else
|
||||
elems = "";
|
||||
{
|
||||
gcry_free (name);
|
||||
name = gcry_sexp_nth_string (l2, 1);
|
||||
gcry_sexp_release (l2);
|
||||
l2 = NULL;
|
||||
if (!name)
|
||||
elems = "";
|
||||
else if (!strcmp (name, "NIST P-256")||!strcmp (name, "nistp256"))
|
||||
gcry_md_write (md, "256\0\0\0\x08nistp256", 15);
|
||||
else if (!strcmp (name, "NIST P-384")||!strcmp (name, "nistp384"))
|
||||
gcry_md_write (md, "384\0\0\0\x08nistp521", 15);
|
||||
else if (!strcmp (name, "NIST P-521")||!strcmp (name, "nistp521"))
|
||||
gcry_md_write (md, "521\0\0\0\x08nistp521", 15);
|
||||
else
|
||||
elems = "";
|
||||
}
|
||||
if (!*elems)
|
||||
err = gpg_err_make (default_errsource, GPG_ERR_UNKNOWN_CURVE);
|
||||
}
|
||||
if (!*elems)
|
||||
err = gpg_err_make (default_errsource, GPG_ERR_UNKNOWN_CURVE);
|
||||
break;
|
||||
|
||||
default:
|
||||
elems = "";
|
||||
err = gpg_err_make (default_errsource, GPG_ERR_PUBKEY_ALGO);
|
||||
@ -133,33 +175,56 @@ get_fingerprint (gcry_sexp_t key, void **r_fpr, size_t *r_len, int as_string)
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
|
||||
for (idx = 0, s = elems; *s; s++, idx++)
|
||||
{
|
||||
gcry_mpi_t a;
|
||||
unsigned char *buf;
|
||||
size_t buflen;
|
||||
|
||||
l2 = gcry_sexp_find_token (list, s, 1);
|
||||
if (!l2)
|
||||
{
|
||||
err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
|
||||
goto leave;
|
||||
}
|
||||
a = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
|
||||
gcry_sexp_release (l2);
|
||||
l2 = NULL;
|
||||
if (!a)
|
||||
if (blobmode)
|
||||
{
|
||||
err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
|
||||
goto leave;
|
||||
}
|
||||
const char *blob;
|
||||
size_t bloblen;
|
||||
unsigned char lenbuf[4];
|
||||
|
||||
err = gcry_mpi_aprint (GCRYMPI_FMT_SSH, &buf, &buflen, a);
|
||||
gcry_mpi_release (a);
|
||||
if (err)
|
||||
goto leave;
|
||||
gcry_md_write (md, buf, buflen);
|
||||
gcry_free (buf);
|
||||
blob = gcry_sexp_nth_data (l2, 1, &bloblen);
|
||||
if (!blob)
|
||||
{
|
||||
err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
|
||||
goto leave;
|
||||
}
|
||||
lenbuf[0] = bloblen >> 24;
|
||||
lenbuf[1] = bloblen >> 16;
|
||||
lenbuf[2] = bloblen >> 8;
|
||||
lenbuf[3] = bloblen;
|
||||
gcry_md_write (md, lenbuf, 4);
|
||||
gcry_md_write (md, blob, bloblen);
|
||||
}
|
||||
else
|
||||
{
|
||||
gcry_mpi_t a;
|
||||
unsigned char *buf;
|
||||
size_t buflen;
|
||||
|
||||
a = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
|
||||
gcry_sexp_release (l2);
|
||||
l2 = NULL;
|
||||
if (!a)
|
||||
{
|
||||
err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = gcry_mpi_aprint (GCRYMPI_FMT_SSH, &buf, &buflen, a);
|
||||
gcry_mpi_release (a);
|
||||
if (err)
|
||||
goto leave;
|
||||
gcry_md_write (md, buf, buflen);
|
||||
gcry_free (buf);
|
||||
}
|
||||
}
|
||||
|
||||
*r_fpr = gcry_malloc (as_string? 61:20);
|
||||
|
Loading…
x
Reference in New Issue
Block a user