mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
Reworked the ECC changes to better fit into the Libgcrypt API.
See ChangeLog for details. Key generation, signing and verification works. Encryption does not yet work. Requires latest Libgcrypt changes.
This commit is contained in:
parent
a58a6b5b78
commit
0fb0bb8d9a
@ -1,3 +1,8 @@
|
||||
2011-01-27 Werner Koch <wk@g10code.com>
|
||||
|
||||
* protect.c (protect_info): Adjust ECDSA and ECDH parameter names.
|
||||
Add "ecc".
|
||||
|
||||
2011-01-19 Werner Koch <wk@g10code.com>
|
||||
|
||||
* trustlist.c (read_one_trustfile): Also chop an CR.
|
||||
|
@ -52,8 +52,9 @@ static struct {
|
||||
{ "rsa", "nedpqu", 2, 5 },
|
||||
{ "dsa", "pqgyx", 4, 4 },
|
||||
{ "elg", "pgyx", 3, 3 },
|
||||
{ "ecdsa","cqd", 2, 2 },
|
||||
{ "ecdh", "cqpd", 3, 3 },
|
||||
{ "ecdsa","pabgnqd", 6, 6 },
|
||||
{ "ecdh", "pabgnqd", 6, 6 },
|
||||
{ "ecc", "pabgnqd", 6, 6 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
@ -1,3 +1,37 @@
|
||||
2011-01-30 Werner Koch <wk@g10code.com>
|
||||
|
||||
|
||||
* keyid.c (keygrip_from_pk): Adjust ECC cases.
|
||||
* pkglue.c (pk_verify): Ditto.
|
||||
|
||||
* parse-packet.c (read_size_body): Rewrite.
|
||||
(parse_key): Simply ECC case.
|
||||
(parse_pubkeyenc): Ditto.
|
||||
|
||||
* misc.c (pubkey_get_npkey): Special case ECC.
|
||||
(pubkey_get_nskey): Ditto.
|
||||
(mpi_print): Support printfing of opaque values.
|
||||
(openpgp_oid_to_str): New.
|
||||
(pubkey_nbits): For ECC pass curve parameter.
|
||||
|
||||
* ecdh.c (pk_ecdh_default_params): Change to return an opaque MPI.
|
||||
|
||||
* build-packet.c (do_key): Automatically handle real and opaque
|
||||
key parameters.
|
||||
(write_fake_data): Return an error code.
|
||||
(mpi_write): Support writing opaque MPIs.
|
||||
(do_pubkey_enc): Simplify ECC handling.
|
||||
|
||||
2011-01-28 Werner Koch <wk@g10code.com>
|
||||
|
||||
* keygen.c (gen_ecc): Rewrite. Select a named curve and create a
|
||||
keyspec based on that.
|
||||
(pk_ecc_build_key_params): Remove.
|
||||
(get_parameter_algo): Map algo number.
|
||||
(ecckey_from_sexp): New.
|
||||
* misc.c (map_pk_gcry_to_openpgp): New.
|
||||
(openpgp_oid_from_str): New. Based on libksba code.
|
||||
|
||||
2011-01-26 Werner Koch <wk@g10code.com>
|
||||
|
||||
* misc.c (ecdsa_qbits_from_Q): Use unsigned int.
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* build-packet.c - assemble packets and write them
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
|
||||
* 2006, 2010 Free Software Foundation, Inc.
|
||||
* 2006, 2010, 2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -159,10 +159,21 @@ build_packet( IOBUF out, PACKET *pkt )
|
||||
*/
|
||||
static int
|
||||
mpi_write (iobuf_t out, gcry_mpi_t a)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
|
||||
{
|
||||
size_t nbits;
|
||||
const void *p;
|
||||
|
||||
p = gcry_mpi_get_opaque (a, &nbits);
|
||||
rc = iobuf_write (out, p, (nbits+7)/8);
|
||||
}
|
||||
else
|
||||
{
|
||||
char buffer[(MAX_EXTERN_MPI_BITS+7)/8+2]; /* 2 is for the mpi length. */
|
||||
size_t nbytes;
|
||||
int rc;
|
||||
|
||||
nbytes = DIM(buffer);
|
||||
rc = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, &nbytes, a );
|
||||
@ -174,6 +185,7 @@ mpi_write (iobuf_t out, gcry_mpi_t a)
|
||||
/* The buffer was too small. We better tell the user about the MPI. */
|
||||
rc = gpg_error (GPG_ERR_TOO_LARGE);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -252,19 +264,20 @@ calc_packet_length( PACKET *pkt )
|
||||
return n;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
static gpg_error_t
|
||||
write_fake_data (IOBUF out, gcry_mpi_t a)
|
||||
{
|
||||
if (a)
|
||||
{
|
||||
unsigned int n;
|
||||
void *p;
|
||||
|
||||
if (!a)
|
||||
return 0;
|
||||
p = gcry_mpi_get_opaque ( a, &n);
|
||||
iobuf_write (out, p, (n+7)/8 );
|
||||
}
|
||||
return iobuf_write (out, p, (n+7)/8 );
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
|
||||
{
|
||||
@ -326,32 +339,10 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
|
||||
}
|
||||
assert (npkey < nskey);
|
||||
|
||||
/* Writing the public parameters is easy. Except if we do an
|
||||
adjustment for ECC OID and possibly KEK params for ECDH. */
|
||||
if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
/* Write DER of OID with preceeding length byte. */
|
||||
err = write_size_body_mpi (a, pk->pkey[0]);
|
||||
if (err)
|
||||
goto leave;
|
||||
/* Write point Q, the public key. */
|
||||
err = mpi_write (a, pk->pkey[1]);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
/* Write one more public field for ECDH. */
|
||||
if (pk->pubkey_algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
err = write_size_body_mpi (a, pk->pkey[2]);
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0; i < npkey; i++ )
|
||||
if ((err = mpi_write (a, pk->pkey[i])))
|
||||
{
|
||||
err = mpi_write (a, pk->pkey[i]);
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
@ -520,20 +511,8 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
|
||||
if ( !n )
|
||||
write_fake_data( a, enc->data[0] );
|
||||
|
||||
if (enc->pubkey_algo == PUBKEY_ALGO_ECDH )
|
||||
{
|
||||
/* The second field persists as a LEN+field structure, even
|
||||
* though it is stored for uniformity as an MPI internally. */
|
||||
assert (n == 2);
|
||||
rc = mpi_write (a, enc->data[0]);
|
||||
if (!rc)
|
||||
rc = write_size_body_mpi (a, enc->data[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0; i < n && !rc ; i++ )
|
||||
rc = mpi_write (a, enc->data[i]);
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
{
|
||||
|
22
g10/ecdh.c
22
g10/ecdh.c
@ -48,16 +48,17 @@ static const struct
|
||||
|
||||
|
||||
|
||||
/* Returns allocated (binary) KEK parameters; the size is returned in
|
||||
sizeout. The caller must free the returned value. Returns NULL
|
||||
and sets ERRNO on error. */
|
||||
byte *
|
||||
pk_ecdh_default_params (unsigned int qbits, size_t *sizeout)
|
||||
/* Return KEK parameters as an opaque MPI The caller must free the
|
||||
returned value. Returns NULL and sets ERRNO on error. */
|
||||
gcry_mpi_t
|
||||
pk_ecdh_default_params (unsigned int qbits)
|
||||
{
|
||||
byte kek_params[4];
|
||||
byte *kek_params;
|
||||
int i;
|
||||
byte *buffer;
|
||||
|
||||
kek_params = xtrymalloc (4);
|
||||
if (!kek_params)
|
||||
return NULL;
|
||||
kek_params[0] = 3; /* Number of bytes to follow. */
|
||||
kek_params[1] = 1; /* Version for KDF+AESWRAP. */
|
||||
|
||||
@ -78,12 +79,7 @@ pk_ecdh_default_params (unsigned int qbits, size_t *sizeout)
|
||||
if (DBG_CIPHER)
|
||||
log_printhex ("ECDH KEK params are", kek_params, sizeof(kek_params) );
|
||||
|
||||
buffer = xtrymalloc (sizeof(kek_params));
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
memcpy (buffer, kek_params, sizeof (kek_params));
|
||||
*sizeout = sizeof (kek_params);
|
||||
return buffer;
|
||||
return gcry_mpi_set_opaque (NULL, kek_params, 4 * 8);
|
||||
}
|
||||
|
||||
|
||||
|
223
g10/keygen.c
223
g10/keygen.c
@ -1081,7 +1081,107 @@ write_keybinding (KBNODE root, PKT_public_key *pri_psk, PKT_public_key *sub_psk,
|
||||
}
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
|
||||
{
|
||||
gpg_error_t err;
|
||||
gcry_sexp_t list, l2;
|
||||
char *curve;
|
||||
int i;
|
||||
const char *oidstr;
|
||||
unsigned int nbits;
|
||||
|
||||
array[0] = NULL;
|
||||
array[1] = NULL;
|
||||
array[2] = NULL;
|
||||
|
||||
list = gcry_sexp_find_token (sexp, "public-key", 0);
|
||||
if (!list)
|
||||
return gpg_error (GPG_ERR_INV_OBJ);
|
||||
l2 = gcry_sexp_cadr (list);
|
||||
gcry_sexp_release (list);
|
||||
list = l2;
|
||||
if (!list)
|
||||
return gpg_error (GPG_ERR_NO_OBJ);
|
||||
|
||||
l2 = gcry_sexp_find_token (list, "curve", 0);
|
||||
if (!l2)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_NO_OBJ);
|
||||
goto leave;
|
||||
}
|
||||
curve = gcry_sexp_nth_string (l2, 1);
|
||||
if (!curve)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_NO_OBJ);
|
||||
goto leave;
|
||||
}
|
||||
gcry_sexp_release (l2);
|
||||
if (!strcmp (curve, "NIST P-256"))
|
||||
{
|
||||
oidstr = "1.2.840.10045.3.1.7";
|
||||
nbits = 256;
|
||||
}
|
||||
else if (!strcmp (curve, "NIST P-384"))
|
||||
{
|
||||
oidstr = "1.3.132.0.34";
|
||||
nbits = 384;
|
||||
}
|
||||
else if (!strcmp (curve, "NIST P-521"))
|
||||
{
|
||||
oidstr = "1.3.132.0.35";
|
||||
nbits = 521;
|
||||
}
|
||||
else
|
||||
{
|
||||
err = gpg_error (GPG_ERR_INV_OBJ);
|
||||
goto leave;
|
||||
}
|
||||
err = openpgp_oid_from_str (oidstr, &array[0]);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
l2 = gcry_sexp_find_token (list, "q", 0);
|
||||
if (!l2)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_NO_OBJ);
|
||||
goto leave;
|
||||
}
|
||||
array[1] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
|
||||
gcry_sexp_release (l2);
|
||||
if (!array[1])
|
||||
{
|
||||
err = gpg_error (GPG_ERR_INV_OBJ);
|
||||
goto leave;
|
||||
}
|
||||
gcry_sexp_release (list);
|
||||
|
||||
if (algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
array[2] = pk_ecdh_default_params (nbits);
|
||||
if (!array[2])
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
leave:
|
||||
if (err)
|
||||
{
|
||||
for (i=0; i < 3; i++)
|
||||
{
|
||||
gcry_mpi_release (array[i]);
|
||||
array[i] = NULL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Extract key parameters from SEXP and store them in ARRAY. ELEMS is
|
||||
a string where each character denotes a parameter name. TOPNAME is
|
||||
the name of the top element above the elements. */
|
||||
static int
|
||||
key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp,
|
||||
const char *topname, const char *elems)
|
||||
@ -1165,6 +1265,9 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
|
||||
pk->expiredate = pk->timestamp + expireval;
|
||||
pk->pubkey_algo = algo;
|
||||
|
||||
if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH)
|
||||
err = ecckey_from_sexp (pk->pkey, s_key, algo);
|
||||
else
|
||||
err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem);
|
||||
if (err)
|
||||
{
|
||||
@ -1173,7 +1276,6 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
|
||||
free_public_key (pk);
|
||||
return err;
|
||||
}
|
||||
gcry_sexp_release (s_key);
|
||||
|
||||
pkt = xtrycalloc (1, sizeof *pkt);
|
||||
if (!pkt)
|
||||
@ -1329,126 +1431,45 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
|
||||
|
||||
|
||||
|
||||
/* Create an S-expression string out of QBITS, ALGO and the TRANSIENT
|
||||
flag. On success a malloced string is returned, on failure NULL
|
||||
and ERRNO is set. */
|
||||
static char *
|
||||
pk_ecc_build_key_params (int qbits, int algo, int transient)
|
||||
{
|
||||
byte *kek_params = NULL;
|
||||
size_t kek_params_size;
|
||||
char qbitsstr[35];
|
||||
char *result;
|
||||
size_t n;
|
||||
|
||||
/* KEK parameters are only needed for long term key generation. */
|
||||
if (!transient && algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
kek_params = pk_ecdh_default_params (qbits, &kek_params_size);
|
||||
if (!kek_params)
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
kek_params = NULL;
|
||||
|
||||
snprintf (qbitsstr, sizeof qbitsstr, "%u", qbits);
|
||||
if (algo == PUBKEY_ALGO_ECDSA || !kek_params)
|
||||
{
|
||||
result = xtryasprintf ("(genkey(%s(nbits %zu:%s)"
|
||||
/**/ "(qbits %zu:%s)"
|
||||
/**/ "(transient-key 1:%d)))",
|
||||
algo == PUBKEY_ALGO_ECDSA ? "ecdsa" : "ecdh",
|
||||
strlen (qbitsstr), qbitsstr,
|
||||
strlen (qbitsstr), qbitsstr,
|
||||
transient);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *tmpstr;
|
||||
|
||||
assert (kek_params);
|
||||
tmpstr = xtryasprintf ("(genkey(ecdh(nbits %zu:%s)"
|
||||
/**/ "(qbits %zu:%s)"
|
||||
/**/ "(transient-key 1:%d)"
|
||||
/**/ "(kek-params %zu:",
|
||||
strlen (qbitsstr), qbitsstr,
|
||||
strlen (qbitsstr), qbitsstr,
|
||||
transient,
|
||||
kek_params_size);
|
||||
if (!tmpstr)
|
||||
{
|
||||
xfree (kek_params);
|
||||
return NULL;
|
||||
}
|
||||
/* Append the binary KEK parmas. */
|
||||
n = strlen (tmpstr);
|
||||
result = xtryrealloc (tmpstr, n + kek_params_size + 4);
|
||||
if (!result)
|
||||
{
|
||||
xfree (tmpstr);
|
||||
xfree (kek_params);
|
||||
return NULL;
|
||||
}
|
||||
memcpy (result + n, kek_params, kek_params_size);
|
||||
strcpy (result + n + kek_params_size, ")))");
|
||||
}
|
||||
xfree (kek_params);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Generate an ECC key
|
||||
*/
|
||||
static gpg_error_t
|
||||
gen_ecc (int algo, unsigned int nbits, KBNODE pub_root,
|
||||
gen_ecc (int algo, unsigned int nbits, kbnode_t pub_root,
|
||||
u32 timestamp, u32 expireval, int is_subkey,
|
||||
int keygen_flags, char **cache_nonce_addr)
|
||||
{
|
||||
int err;
|
||||
unsigned int qbits;
|
||||
gpg_error_t err;
|
||||
const char *curve;
|
||||
char *keyparms;
|
||||
|
||||
assert (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH);
|
||||
|
||||
if (pubkey_get_npkey (PUBKEY_ALGO_ECDSA) != 2
|
||||
|| pubkey_get_nskey (PUBKEY_ALGO_ECDSA) != 3
|
||||
|| pubkey_get_npkey (PUBKEY_ALGO_ECDH) != 3
|
||||
|| pubkey_get_nskey (PUBKEY_ALGO_ECDH) != 4)
|
||||
{
|
||||
log_error ("broken version of Libgcrypt\n");
|
||||
return gpg_error (GPG_ERR_INTERNAL); /* ABI silently changed. */
|
||||
}
|
||||
/* For now we may only use one of the 3 NISY curves. */
|
||||
if (nbits <= 256)
|
||||
curve = "NIST P-256";
|
||||
else if (nbits <= 384)
|
||||
curve = "NIST P-384";
|
||||
else
|
||||
curve = "NIST P-521";
|
||||
|
||||
if (nbits != 256 && nbits != 384 && nbits != 521)
|
||||
{
|
||||
log_info (_("keysize invalid; using %u bits\n"), 256);
|
||||
/* FIXME: Where do we set it to 256? */
|
||||
}
|
||||
|
||||
/* Figure out a Q size based on the key size. See gen_dsa for more
|
||||
details. Due to 8-bit rounding we may get 528 here instead of 521. */
|
||||
nbits = qbits = (nbits < 521 ? nbits : 521 );
|
||||
|
||||
keyparms = pk_ecc_build_key_params
|
||||
(qbits, algo, !!( (keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
|
||||
&& (keygen_flags & KEYGEN_FLAG_NO_PROTECTION)) );
|
||||
keyparms = xtryasprintf ("(genkey(%s(curve %zu:%s)%s))",
|
||||
algo == PUBKEY_ALGO_ECDSA ? "ecdsa" : "ecdh",
|
||||
strlen (curve), curve,
|
||||
((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
|
||||
&& (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
|
||||
"(transient-key)" : "" );
|
||||
if (!keyparms)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_error ("ecc pk_ecc_build_key_params failed: %s\n",
|
||||
gpg_strerror (err));
|
||||
}
|
||||
else
|
||||
{
|
||||
err = common_gen (keyparms, algo,
|
||||
algo == PUBKEY_ALGO_ECDSA? "cq" : "cqp",
|
||||
err = common_gen (keyparms, algo, "",
|
||||
pub_root, timestamp, expireval, is_subkey,
|
||||
keygen_flags, cache_nonce_addr);
|
||||
xfree (keyparms);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@ -2428,7 +2449,7 @@ get_parameter_algo( struct para_data_s *para, enum para_name key,
|
||||
|| !strcmp (r->u.value, "ELG"))
|
||||
i = GCRY_PK_ELG_E;
|
||||
else
|
||||
i = gcry_pk_map_name (r->u.value);
|
||||
i = map_pk_gcry_to_openpgp (gcry_pk_map_name (r->u.value));
|
||||
|
||||
if (i == PUBKEY_ALGO_RSA_E || i == PUBKEY_ALGO_RSA_S)
|
||||
i = 0; /* we don't want to allow generation of these algorithms */
|
||||
|
19
g10/keyid.c
19
g10/keyid.c
@ -724,17 +724,20 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array)
|
||||
|
||||
case PUBKEY_ALGO_ECDSA:
|
||||
case PUBKEY_ALGO_ECDH:
|
||||
{
|
||||
char *curve = openpgp_oid_to_str (pk->pkey[0]);
|
||||
if (!curve)
|
||||
err = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
err = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(ecc(c%m)(q%m)))",
|
||||
pk->pkey[0], pk->pkey[1]);
|
||||
"(public-key(ecc(curve%s)(q%m)))",
|
||||
curve, pk->pkey[1]);
|
||||
xfree (curve);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* case PUBKEY_ALGO_ECDH: */
|
||||
/* err = gcry_sexp_build (&s_pkey, NULL, */
|
||||
/* "(public-key(ecdh(c%m)(q%m)(p%m)))", */
|
||||
/* pk->pkey[0], pk->pkey[1], pk->pkey[2]); */
|
||||
/* break; */
|
||||
|
||||
default:
|
||||
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
break;
|
||||
|
11
g10/main.h
11
g10/main.h
@ -97,6 +97,7 @@ int openpgp_cipher_blocklen (int algo);
|
||||
int openpgp_cipher_test_algo( int algo );
|
||||
const char *openpgp_cipher_algo_name (int algo);
|
||||
int map_pk_openpgp_to_gcry (int algo);
|
||||
int map_pk_gcry_to_openpgp (enum gcry_pk_algos algo);
|
||||
int openpgp_pk_test_algo( int algo );
|
||||
int openpgp_pk_test_algo2 ( int algo, unsigned int use );
|
||||
int openpgp_pk_algo_usage ( int algo );
|
||||
@ -154,15 +155,21 @@ int is_valid_mailbox (const char *name);
|
||||
const char *get_libexecdir (void);
|
||||
int path_access(const char *file,int mode);
|
||||
|
||||
/* Temporary helpers. */
|
||||
int pubkey_get_npkey( int algo );
|
||||
int pubkey_get_nskey( int algo );
|
||||
int pubkey_get_nsig( int algo );
|
||||
int pubkey_get_nenc( int algo );
|
||||
|
||||
/* Temporary helpers. */
|
||||
unsigned int pubkey_nbits( int algo, gcry_mpi_t *pkey );
|
||||
int mpi_print (estream_t stream, gcry_mpi_t a, int mode);
|
||||
unsigned int ecdsa_qbits_from_Q (unsigned int qbits);
|
||||
|
||||
/* Other stuff */
|
||||
gpg_error_t openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi);
|
||||
char *openpgp_oid_to_str (gcry_mpi_t a);
|
||||
|
||||
|
||||
/*-- status.c --*/
|
||||
void set_status_fd ( int fd );
|
||||
int is_status_enabled ( void );
|
||||
@ -300,7 +307,7 @@ gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec,
|
||||
int export_seckeys (ctrl_t ctrl, strlist_t users);
|
||||
int export_secsubkeys (ctrl_t ctrl, strlist_t users);
|
||||
|
||||
/* dearmor.c --*/
|
||||
/*-- dearmor.c --*/
|
||||
int dearmor_file( const char *fname );
|
||||
int enarmor_file( const char *fname );
|
||||
|
||||
|
292
g10/misc.c
292
g10/misc.c
@ -379,6 +379,19 @@ map_pk_openpgp_to_gcry (int algo)
|
||||
}
|
||||
}
|
||||
|
||||
/* Map Gcrypt public key algorithm numbers to those used by
|
||||
OpenPGP. */
|
||||
int
|
||||
map_pk_gcry_to_openpgp (enum gcry_pk_algos algo)
|
||||
{
|
||||
switch (algo)
|
||||
{
|
||||
case GCRY_PK_ECDSA: return PUBKEY_ALGO_ECDSA;
|
||||
case GCRY_PK_ECDH: return PUBKEY_ALGO_ECDH;
|
||||
default: return algo < 110 ? algo : 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Return the block length of an OpenPGP cipher algorithm. */
|
||||
int
|
||||
@ -1347,35 +1360,44 @@ path_access(const char *file,int mode)
|
||||
|
||||
|
||||
|
||||
/* Temporary helper. */
|
||||
/* Return the number of public key parameters as used by OpenPGP. */
|
||||
int
|
||||
pubkey_get_npkey (int algo)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
/* ECC is special. */
|
||||
if (algo == PUBKEY_ALGO_ECDSA)
|
||||
return 2;
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
return 3;
|
||||
|
||||
/* All other algorithms match those of Libgcrypt. */
|
||||
if (algo == GCRY_PK_ELG_E)
|
||||
algo = GCRY_PK_ELG;
|
||||
else if (algo == PUBKEY_ALGO_ECDSA)
|
||||
algo = GCRY_PK_ECDSA;
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
algo = GCRY_PK_ECDH;
|
||||
|
||||
if (gcry_pk_algo_info (algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &n))
|
||||
n = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Temporary helper. */
|
||||
|
||||
/* Return the number of secret key parameters as used by OpenPGP. */
|
||||
int
|
||||
pubkey_get_nskey (int algo)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
/* ECC is special. */
|
||||
if (algo == PUBKEY_ALGO_ECDSA)
|
||||
return 3;
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
return 4;
|
||||
|
||||
/* All other algorithms match those of Libgcrypt. */
|
||||
if (algo == GCRY_PK_ELG_E)
|
||||
algo = GCRY_PK_ELG;
|
||||
else if (algo == PUBKEY_ALGO_ECDSA)
|
||||
algo = GCRY_PK_ECDSA;
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
algo = GCRY_PK_ECDH;
|
||||
|
||||
if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &n ))
|
||||
n = 0;
|
||||
return n;
|
||||
@ -1387,29 +1409,36 @@ pubkey_get_nsig( int algo )
|
||||
{
|
||||
size_t n;
|
||||
|
||||
/* ECC is special. */
|
||||
if (algo == PUBKEY_ALGO_ECDSA)
|
||||
return 2;
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
return 0;
|
||||
|
||||
if (algo == GCRY_PK_ELG_E)
|
||||
algo = GCRY_PK_ELG;
|
||||
else if (algo == PUBKEY_ALGO_ECDSA)
|
||||
algo = GCRY_PK_ECDSA;
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
algo = GCRY_PK_ECDH;
|
||||
|
||||
if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NSIGN, NULL, &n))
|
||||
n = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/* Temporary helper. */
|
||||
int
|
||||
pubkey_get_nenc (int algo)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
/* ECC is special. */
|
||||
if (algo == PUBKEY_ALGO_ECDSA)
|
||||
return 0;
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
return 2;
|
||||
|
||||
if (algo == GCRY_PK_ELG_E)
|
||||
algo = GCRY_PK_ELG;
|
||||
else if (algo == PUBKEY_ALGO_ECDSA)
|
||||
algo = GCRY_PK_ECDSA;
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
algo = GCRY_PK_ECDH;
|
||||
|
||||
if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NENCR, NULL, &n ))
|
||||
n = 0;
|
||||
return n;
|
||||
@ -1442,9 +1471,16 @@ pubkey_nbits( int algo, gcry_mpi_t *key )
|
||||
key[0], key[1] );
|
||||
}
|
||||
else if( algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH ) {
|
||||
char *curve = openpgp_oid_to_str (key[0]);
|
||||
if (!curve)
|
||||
rc = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
rc = gcry_sexp_build (&sexp, NULL,
|
||||
"(public-key(ecc(c%m)(q%m)))",
|
||||
key[0], key[1] /* not affecting the size calculation, so use 'ecc' == 'ecdsa' */ );
|
||||
"(public-key(ecc(curve%s)(q%m)))",
|
||||
curve, key[1]);
|
||||
xfree (curve);
|
||||
}
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
@ -1472,6 +1508,19 @@ mpi_print (estream_t fp, gcry_mpi_t a, int mode)
|
||||
n1 = gcry_mpi_get_nbits(a);
|
||||
n += es_fprintf (fp, "[%u bits]", n1);
|
||||
}
|
||||
else if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
|
||||
{
|
||||
unsigned int nbits;
|
||||
unsigned char *p = gcry_mpi_get_opaque (a, &nbits);
|
||||
if (!p)
|
||||
n += es_fprintf (fp, "[invalid opaque value]");
|
||||
else
|
||||
{
|
||||
nbits = (nbits + 7)/8;
|
||||
for (; nbits; nbits--, p++)
|
||||
n += es_fprintf (fp, "%02X", *p);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned char *buffer;
|
||||
@ -1501,3 +1550,206 @@ ecdsa_qbits_from_Q (unsigned int qbits)
|
||||
qbits /= 2;
|
||||
return qbits;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Helper for openpgp_oid_from_str. */
|
||||
static size_t
|
||||
make_flagged_int (unsigned long value, char *buf, size_t buflen)
|
||||
{
|
||||
int more = 0;
|
||||
int shift;
|
||||
|
||||
/* fixme: figure out the number of bits in an ulong and start with
|
||||
that value as shift (after making it a multiple of 7) a more
|
||||
straigtforward implementation is to do it in reverse order using
|
||||
a temporary buffer - saves a lot of compares */
|
||||
for (more=0, shift=28; shift > 0; shift -= 7)
|
||||
{
|
||||
if (more || value >= (1<<shift))
|
||||
{
|
||||
buf[buflen++] = 0x80 | (value >> shift);
|
||||
value -= (value >> shift) << shift;
|
||||
more = 1;
|
||||
}
|
||||
}
|
||||
buf[buflen++] = value;
|
||||
return buflen;
|
||||
}
|
||||
|
||||
|
||||
/* Convert the OID given in dotted decimal form in STRING to an DER
|
||||
* encoding and store it as an opaque value at R_MPI. The format of
|
||||
* the DER encoded is not a regular ASN.1 object but the modified
|
||||
* format as used by OpenPGP for the ECC curve description. On error
|
||||
* the function returns and error code an NULL is stored at R_BUG.
|
||||
* Note that scanning STRING stops at the first white space
|
||||
* character. */
|
||||
gpg_error_t
|
||||
openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi)
|
||||
{
|
||||
unsigned char *buf;
|
||||
size_t buflen;
|
||||
unsigned long val1, val;
|
||||
const char *endp;
|
||||
int arcno;
|
||||
|
||||
*r_mpi = NULL;
|
||||
|
||||
if (!string || !*string)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
||||
/* We can safely assume that the encoded OID is shorter than the string. */
|
||||
buf = xtrymalloc (1 + strlen (string) + 2);
|
||||
if (!buf)
|
||||
return gpg_error_from_syserror ();
|
||||
/* Save the first byte for the length. */
|
||||
buflen = 1;
|
||||
|
||||
val1 = 0; /* Avoid compiler warning. */
|
||||
arcno = 0;
|
||||
do {
|
||||
arcno++;
|
||||
val = strtoul (string, (char**)&endp, 10);
|
||||
if (!digitp (string) || !(*endp == '.' || !*endp))
|
||||
{
|
||||
xfree (buf);
|
||||
return gpg_error (GPG_ERR_INV_OID_STRING);
|
||||
}
|
||||
if (*endp == '.')
|
||||
string = endp+1;
|
||||
|
||||
if (arcno == 1)
|
||||
{
|
||||
if (val > 2)
|
||||
break; /* Not allowed, error catched below. */
|
||||
val1 = val;
|
||||
}
|
||||
else if (arcno == 2)
|
||||
{ /* Need to combine the first two arcs in one octet. */
|
||||
if (val1 < 2)
|
||||
{
|
||||
if (val > 39)
|
||||
{
|
||||
xfree (buf);
|
||||
return gpg_error (GPG_ERR_INV_OID_STRING);
|
||||
}
|
||||
buf[buflen++] = val1*40 + val;
|
||||
}
|
||||
else
|
||||
{
|
||||
val += 80;
|
||||
buflen = make_flagged_int (val, buf, buflen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buflen = make_flagged_int (val, buf, buflen);
|
||||
}
|
||||
} while (*endp == '.');
|
||||
|
||||
if (arcno == 1 || buflen < 2 || buflen > 254 )
|
||||
{ /* It is not possible to encode only the first arc. */
|
||||
xfree (buf);
|
||||
return gpg_error (GPG_ERR_INV_OID_STRING);
|
||||
}
|
||||
|
||||
*buf = buflen - 1;
|
||||
*r_mpi = gcry_mpi_set_opaque (NULL, buf, buflen * 8);
|
||||
if (!*r_mpi)
|
||||
{
|
||||
xfree (buf);
|
||||
return gpg_error_from_syserror ();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Return a malloced string represenation of the OID in the opaque MPI
|
||||
A. In case of an error NULL is returned and ERRNO is set. */
|
||||
char *
|
||||
openpgp_oid_to_str (gcry_mpi_t a)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
size_t length;
|
||||
char *string, *p;
|
||||
int n = 0;
|
||||
unsigned long val, valmask;
|
||||
|
||||
valmask = (unsigned long)0xfe << (8 * (sizeof (valmask) - 1));
|
||||
|
||||
if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
|
||||
{
|
||||
gpg_err_set_errno (EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = gcry_mpi_get_opaque (a, &length);
|
||||
length = (length+7)/8;
|
||||
|
||||
/* The first bytes gives the length; check consistency. */
|
||||
if (!length || buf[0] != length -1)
|
||||
{
|
||||
gpg_err_set_errno (EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
/* Skip length byte. */
|
||||
length--;
|
||||
buf++;
|
||||
|
||||
/* To calculate the length of the string we can safely assume an
|
||||
upper limit of 3 decimal characters per byte. Two extra bytes
|
||||
account for the special first octect */
|
||||
string = p = xtrymalloc (length*(1+3)+2+1);
|
||||
if (!string)
|
||||
return NULL;
|
||||
if (!buf || !length)
|
||||
{
|
||||
*p = 0;
|
||||
return string;
|
||||
}
|
||||
|
||||
if (buf[0] < 40)
|
||||
p += sprintf (p, "0.%d", buf[n]);
|
||||
else if (buf[0] < 80)
|
||||
p += sprintf (p, "1.%d", buf[n]-40);
|
||||
else {
|
||||
val = buf[n] & 0x7f;
|
||||
while ( (buf[n]&0x80) && ++n < length )
|
||||
{
|
||||
if ( (val & valmask) )
|
||||
goto badoid; /* Overflow. */
|
||||
val <<= 7;
|
||||
val |= buf[n] & 0x7f;
|
||||
}
|
||||
val -= 80;
|
||||
sprintf (p, "2.%lu", val);
|
||||
p += strlen (p);
|
||||
}
|
||||
for (n++; n < length; n++)
|
||||
{
|
||||
val = buf[n] & 0x7f;
|
||||
while ( (buf[n]&0x80) && ++n < length )
|
||||
{
|
||||
if ( (val & valmask) )
|
||||
goto badoid; /* Overflow. */
|
||||
val <<= 7;
|
||||
val |= buf[n] & 0x7f;
|
||||
}
|
||||
sprintf (p, ".%lu", val);
|
||||
p += strlen (p);
|
||||
}
|
||||
|
||||
*p = 0;
|
||||
return string;
|
||||
|
||||
badoid:
|
||||
/* Return a special OID (gnu.gnupg.badoid) to indicate the error
|
||||
case. The OID is broken and thus we return one which can't do
|
||||
any harm. Formally this does not need to be a bad OID but an OID
|
||||
with an arc that can't be represented in a 32 bit word is more
|
||||
than likely corrupt. */
|
||||
xfree (string);
|
||||
return xtrystrdup ("1.3.6.1.4.1.11591.2.12242973");
|
||||
}
|
||||
|
||||
|
@ -741,51 +741,57 @@ read_rest (IOBUF inp, size_t pktlen, int partial)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read a special size+body from inp into body[body_max_size] and
|
||||
* return it in a buffer and as MPI. On success the number of
|
||||
* consumed bytes will body[0]+1. The format of the content of the
|
||||
* returned MPI is one byte LEN, following by LEN bytes. Caller is
|
||||
* expected to pre-allocate fixed-size 255 byte buffer (or smaller
|
||||
* when appropriate).
|
||||
*/
|
||||
static int
|
||||
read_size_body (iobuf_t inp, byte *body, int body_max_size,
|
||||
int pktlen, gcry_mpi_t *out )
|
||||
/* Read a special size+body from INP. On success store an opaque MPI
|
||||
with it at R_DATA. On error return an error code and store NULL at
|
||||
R_DATA. Even in the error case store the number of read bytes at
|
||||
R_NREAD. The caller shall pass the remaining size of the packet in
|
||||
PKTLEN. */
|
||||
static gpg_error_t
|
||||
read_size_body (iobuf_t inp, int pktlen, size_t *r_nread,
|
||||
gcry_mpi_t *r_data)
|
||||
{
|
||||
unsigned int n;
|
||||
int rc;
|
||||
gcry_mpi_t result;
|
||||
char buffer[256];
|
||||
char *tmpbuf;
|
||||
int i, c, nbytes;
|
||||
|
||||
*out = NULL;
|
||||
*r_nread = 0;
|
||||
*r_data = NULL;
|
||||
|
||||
if( (n = iobuf_readbyte(inp)) == -1 )
|
||||
{
|
||||
return G10ERR_INVALID_PACKET;
|
||||
}
|
||||
if ( n >= body_max_size || n < 2)
|
||||
{
|
||||
log_error("invalid size+body field\n");
|
||||
return G10ERR_INVALID_PACKET;
|
||||
}
|
||||
body[0] = n;
|
||||
if ((n = iobuf_read(inp, body+1, n)) == -1)
|
||||
{
|
||||
log_error("invalid size+body field\n");
|
||||
return G10ERR_INVALID_PACKET;
|
||||
}
|
||||
if (n+1 > pktlen)
|
||||
{
|
||||
log_error("size+body field is larger than the packet\n");
|
||||
return G10ERR_INVALID_PACKET;
|
||||
}
|
||||
rc = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, body, n+1, NULL);
|
||||
if (rc)
|
||||
log_fatal ("mpi_scan failed: %s\n", gpg_strerror (rc));
|
||||
if (!pktlen)
|
||||
return gpg_error (GPG_ERR_INV_PACKET);
|
||||
c = iobuf_readbyte (inp);
|
||||
if (c < 0)
|
||||
return gpg_error (GPG_ERR_INV_PACKET);
|
||||
pktlen--;
|
||||
++*r_nread;
|
||||
nbytes = c;
|
||||
if (nbytes < 2 || nbytes > 254)
|
||||
return gpg_error (GPG_ERR_INV_PACKET);
|
||||
if (nbytes > pktlen)
|
||||
return gpg_error (GPG_ERR_INV_PACKET);
|
||||
|
||||
*out = result;
|
||||
buffer[0] = nbytes;
|
||||
|
||||
return rc;
|
||||
for (i = 0; i < nbytes; i++)
|
||||
{
|
||||
c = iobuf_get (inp);
|
||||
if (c < 0)
|
||||
return gpg_error (GPG_ERR_INV_PACKET);
|
||||
++*r_nread;
|
||||
buffer[1+i] = c;
|
||||
}
|
||||
|
||||
tmpbuf = xtrymalloc (1 + nbytes);
|
||||
if (!tmpbuf)
|
||||
return gpg_error_from_syserror ();
|
||||
memcpy (tmpbuf, buffer, 1 + nbytes);
|
||||
*r_data = gcry_mpi_set_opaque (NULL, tmpbuf, 8 * (1 + nbytes));
|
||||
if (!*r_data)
|
||||
{
|
||||
xfree (tmpbuf);
|
||||
return gpg_error_from_syserror ();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -988,46 +994,29 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (k->pubkey_algo == PUBKEY_ALGO_ECDH)
|
||||
for (i = 0; i < ndata; i++)
|
||||
{
|
||||
byte encr_buf[255];
|
||||
|
||||
assert (ndata == 2);
|
||||
n = pktlen;
|
||||
k->data[0] = mpi_read (inp, &n, 0);
|
||||
if (k->pubkey_algo == PUBKEY_ALGO_ECDH && i == 1)
|
||||
{
|
||||
rc = read_size_body (inp, pktlen, &n, k->data+i);
|
||||
pktlen -= n;
|
||||
rc = read_size_body (inp, encr_buf, sizeof(encr_buf),
|
||||
pktlen, k->data+1);
|
||||
if (rc)
|
||||
goto leave;
|
||||
|
||||
if (list_mode)
|
||||
{
|
||||
es_fprintf (listfp, "\tdata: ");
|
||||
mpi_print (listfp, k->data[0], mpi_print_mode );
|
||||
es_putc ('\n', listfp);
|
||||
es_fprintf (listfp, "\tdata: [% 3d bytes] ", encr_buf[0]+1);
|
||||
mpi_print (listfp, k->data[1], mpi_print_mode );
|
||||
es_putc ('\n', listfp);
|
||||
}
|
||||
pktlen -= (encr_buf[0]+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < ndata; i++)
|
||||
{
|
||||
n = pktlen;
|
||||
k->data[i] = mpi_read (inp, &n, 0);
|
||||
pktlen -= n;
|
||||
if (!k->data[i])
|
||||
rc = gpg_error (GPG_ERR_INV_PACKET);
|
||||
}
|
||||
if (rc)
|
||||
goto leave;
|
||||
if (list_mode)
|
||||
{
|
||||
es_fprintf (listfp, "\tdata: ");
|
||||
mpi_print (listfp, k->data[i], mpi_print_mode);
|
||||
es_putc ('\n', listfp);
|
||||
}
|
||||
if (!k->data[i])
|
||||
rc = gpg_error (GPG_ERR_INV_PACKET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1989,7 +1978,6 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
|
||||
unknown_pubkey_warning (algorithm);
|
||||
}
|
||||
|
||||
|
||||
if (!npkey)
|
||||
{
|
||||
/* Unknown algorithm - put data into an opaque MPI. */
|
||||
@ -2001,79 +1989,32 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Fill in public key parameters. */
|
||||
if (algorithm == PUBKEY_ALGO_ECDSA || algorithm == PUBKEY_ALGO_ECDH)
|
||||
for (i = 0; i < npkey; i++)
|
||||
{
|
||||
/* FIXME: The code in this function ignores the errors. */
|
||||
byte name_oid[256];
|
||||
|
||||
err = read_size_body (inp, name_oid, sizeof(name_oid),
|
||||
pktlen, pk->pkey+0);
|
||||
if (err)
|
||||
goto leave;
|
||||
n = name_oid[0];
|
||||
if (list_mode)
|
||||
es_fprintf (listfp, "\tpkey[0]: curve OID [%d] ...%02x %02x\n",
|
||||
n, name_oid[1+n-2], name_oid[1+n-1]);
|
||||
pktlen -= (n+1);
|
||||
/* Set item [1], which corresponds to the public key; these
|
||||
two fields are all we need to uniquely define the key/ */
|
||||
n = pktlen;
|
||||
pk->pkey[1] = mpi_read( inp, &n, 0 );
|
||||
if ((algorithm == PUBKEY_ALGO_ECDSA
|
||||
|| algorithm == PUBKEY_ALGO_ECDH) && (i==0 || i == 2))
|
||||
{
|
||||
err = read_size_body (inp, pktlen, &n, pk->pkey+i);
|
||||
pktlen -= n;
|
||||
if (!pk->pkey[1])
|
||||
err = gpg_error (GPG_ERR_INV_PACKET);
|
||||
else if (list_mode)
|
||||
{
|
||||
es_fprintf (listfp, "\tpkey[1]: ");
|
||||
mpi_print (listfp, pk->pkey[1], mpi_print_mode);
|
||||
es_putc ('\n', listfp);
|
||||
}
|
||||
/* One more field for ECDH. */
|
||||
if (algorithm == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
/* (NAMEOID holds the KEK params.) */
|
||||
err = read_size_body (inp, name_oid, sizeof(name_oid),
|
||||
pktlen, pk->pkey+2);
|
||||
if (err)
|
||||
goto leave;
|
||||
n = name_oid[0];
|
||||
if (name_oid[1] != 1)
|
||||
{
|
||||
log_error ("invalid ecdh KEK parameters field type in "
|
||||
"private key: understand type 1, "
|
||||
"but found 0x%02x\n", name_oid[1]);
|
||||
err = gpg_error (GPG_ERR_INV_PACKET);
|
||||
goto leave;
|
||||
}
|
||||
if (list_mode)
|
||||
es_fprintf (listfp, "\tpkey[2]: KEK params type=01 "
|
||||
"hash:%d sym-algo:%d\n",
|
||||
name_oid[1+n-2], name_oid[1+n-1]);
|
||||
pktlen -= (n+1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < npkey; i++)
|
||||
{
|
||||
n = pktlen;
|
||||
pk->pkey[i] = mpi_read (inp, &n, 0);
|
||||
pktlen -= n;
|
||||
if (!pk->pkey[i])
|
||||
err = gpg_error (GPG_ERR_INV_PACKET);
|
||||
}
|
||||
if (err)
|
||||
goto leave;
|
||||
if (list_mode)
|
||||
{
|
||||
es_fprintf (listfp, "\tpkey[%d]: ", i);
|
||||
mpi_print (listfp, pk->pkey[i], mpi_print_mode);
|
||||
es_putc ('\n', listfp);
|
||||
}
|
||||
if (!pk->pkey[i])
|
||||
err = gpg_error (GPG_ERR_INV_PACKET);
|
||||
}
|
||||
}
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (list_mode)
|
||||
keyid_from_pk (pk, keyid);
|
||||
|
||||
|
34
g10/pkglue.c
34
g10/pkglue.c
@ -78,9 +78,17 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey)
|
||||
"(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
|
||||
}
|
||||
else if (pkalgo == GCRY_PK_ECDSA) /* Same as GCRY_PK_ECDH */
|
||||
{
|
||||
char *curve = openpgp_oid_to_str (pkey[0]);
|
||||
if (!curve)
|
||||
rc = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
rc = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(ecdsa(c%m)(q%m)))", pkey[0], pkey[1]);
|
||||
"(public-key(ecdsa(curve %s)(q%m)))",
|
||||
curve, pkey[1]);
|
||||
xfree (curve);
|
||||
}
|
||||
}
|
||||
else
|
||||
return GPG_ERR_PUBKEY_ALGO;
|
||||
@ -174,19 +182,28 @@ pk_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data,
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
gcry_mpi_t k;
|
||||
char *curve;
|
||||
|
||||
rc = pk_ecdh_generate_ephemeral_key (pkey, &k);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
curve = openpgp_oid_to_str (pkey[0]);
|
||||
if (!curve)
|
||||
rc = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
/* Now use the ephemeral secret to compute the shared point. */
|
||||
rc = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(ecdh(c%m)(q%m)(p%m)))",
|
||||
pkey[0], pkey[1], pkey[2]);
|
||||
"(public-key(ecdh(curve%s)(q%m)))",
|
||||
curve, pkey[1]);
|
||||
xfree (curve);
|
||||
/* FIXME: Take care of RC. */
|
||||
/* Put K into a simplified S-expression. */
|
||||
if (rc || gcry_sexp_build (&s_data, NULL, "%m", k))
|
||||
BUG ();
|
||||
}
|
||||
}
|
||||
else
|
||||
return gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
|
||||
@ -271,10 +288,17 @@ pk_check_secret_key (int algo, gcry_mpi_t *skey)
|
||||
skey[5]);
|
||||
}
|
||||
else if (gcry_pkalgo == GCRY_PK_ECDSA || gcry_pkalgo == GCRY_PK_ECDH)
|
||||
{
|
||||
char *curve = openpgp_oid_to_str (skey[0]);
|
||||
if (!curve)
|
||||
rc = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
rc = gcry_sexp_build (&s_skey, NULL,
|
||||
"(private-key(ecdsa(c%m)(q%m)(d%m)))",
|
||||
skey[0], skey[1], skey[2] );
|
||||
"(private-key(ecdsa(curve%s)(q%m)(d%m)))",
|
||||
curve, skey[1], skey[2]);
|
||||
xfree (curve);
|
||||
}
|
||||
}
|
||||
else
|
||||
return GPG_ERR_PUBKEY_ALGO;
|
||||
|
@ -32,7 +32,7 @@ int pk_check_secret_key (int algo, gcry_mpi_t *skey);
|
||||
|
||||
|
||||
/*-- ecdh.c --*/
|
||||
byte *pk_ecdh_default_params (unsigned int qbits, size_t *sizeout);
|
||||
gcry_mpi_t pk_ecdh_default_params (unsigned int qbits);
|
||||
gpg_error_t pk_ecdh_generate_ephemeral_key (gcry_mpi_t *pkey, gcry_mpi_t *r_k);
|
||||
gpg_error_t pk_ecdh_encrypt_with_shared_point
|
||||
/* */ (int is_encrypt, gcry_mpi_t shared_mpi,
|
||||
|
Loading…
x
Reference in New Issue
Block a user