diff options
author | Werner Koch <[email protected]> | 2020-02-09 23:31:07 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2023-01-13 13:54:20 +0000 |
commit | 2e39fed1091077c6b55b375c1755d06e199ee4e9 (patch) | |
tree | 44a6fba1e1bb26bf4e92973e84cf52d80772f8cc | |
parent | scd: Return CARDTYPE, CARDVERSION, and APPVERSION. (diff) | |
download | gnupg-2e39fed1091077c6b55b375c1755d06e199ee4e9.tar.gz gnupg-2e39fed1091077c6b55b375c1755d06e199ee4e9.zip |
common: New function get_keyalgo_string.
* common/openpgp-oid.c (struct keyalgo_string_s): New.
(keyalgo_strings): New.
(keyalgo_strings_size, keyalgo_strings_used): New.
(openpgp_oid_or_name_to_curve): New.
(get_keyalgo_string): New.
--
This function is intended as a more general version of gpg's
pubkey_string function. It has the advantage to avoid mallocs and
uses static table of algorithm strings instead. There should be only
a few dozen of such strings (if at all) and thus all those allocations
we do internally in gpg's pubkey_string and the static buffers all
over the place are not too nice.
Signed-off-by: Werner Koch <[email protected]>
(cherry picked from commit 3a1fa13eedb969b561bae18cd3d7c2fb0b63d6ab)
(cherry picked from commit 332a72f7340895e7db1e9c5f89046f722bb7465b)
-rw-r--r-- | common/openpgp-oid.c | 165 | ||||
-rw-r--r-- | common/t-openpgp-oid.c | 73 | ||||
-rw-r--r-- | common/util.h | 3 | ||||
-rw-r--r-- | g10/keyid.c | 5 |
4 files changed, 240 insertions, 6 deletions
diff --git a/common/openpgp-oid.c b/common/openpgp-oid.c index 943fe3ea6..9d8b2d351 100644 --- a/common/openpgp-oid.c +++ b/common/openpgp-oid.c @@ -71,6 +71,21 @@ static const char oid_ed25519[] = static const char oid_cv25519[] = { 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01 }; +/* A table to store keyalgo strings like "rsa2048 or "ed25519" so that + * we do not need to allocate them. This is currently a simple array + * but may eventually be changed to a fast data structure. Noet that + * unknown algorithms are stored with (NBITS,CURVE) set to (0,NULL). */ +struct keyalgo_string_s +{ + enum gcry_pk_algos algo; /* Mandatory. */ + unsigned int nbits; /* Size for classical algos. */ + char *curve; /* Curvename (OID) or NULL. */ + char *name; /* Allocated name. */ +}; +static struct keyalgo_string_s *keyalgo_strings; /* The table. */ +static size_t keyalgo_strings_size; /* Allocated size. */ +static size_t keyalgo_strings_used; /* Used size. */ + /* Helper for openpgp_oid_from_str. */ static size_t @@ -383,9 +398,9 @@ openpgp_curve_to_oid (const char *name, unsigned int *r_nbits, int *r_algo) } -/* Map an OpenPGP OID to the Libgcrypt curve NAME. Returns NULL for - unknown curve names. Unless CANON is set we prefer an alias name - here which is more suitable for printing. */ +/* Map an OpenPGP OID to the Libgcrypt curve name. Returns NULL for + * unknown curve names. Unless CANON is set we prefer an alias name + * here which is more suitable for printing. */ const char * openpgp_oid_to_curve (const char *oidstr, int canon) { @@ -402,6 +417,27 @@ openpgp_oid_to_curve (const char *oidstr, int canon) } +/* Map an OpenPGP OID, name or alias to the Libgcrypt curve name. + * Returns NULL for unknown curve names. Unless CANON is set we + * prefer an alias name here which is more suitable for printing. */ +const char * +openpgp_oid_or_name_to_curve (const char *oidname, int canon) +{ + int i; + + if (!oidname) + return NULL; + + for (i=0; oidtable[i].name; i++) + if (!strcmp (oidtable[i].oidstr, oidname) + || !strcmp (oidtable[i].name, oidname) + || (oidtable[i].alias &&!strcmp (oidtable[i].alias, oidname))) + return !canon && oidtable[i].alias? oidtable[i].alias : oidtable[i].name; + + return NULL; +} + + /* Return true if the curve with NAME is supported. */ static int curve_supported_p (const char *name) @@ -470,3 +506,126 @@ openpgp_is_curve_supported (const char *name, int *r_algo, } return NULL; } + + +/* Map an OpenPGP public key algorithm number to the one used by + * Libgcrypt. Returns 0 for unknown gcry algorithm. */ +enum gcry_pk_algos +map_openpgp_pk_to_gcry (pubkey_algo_t algo) +{ + switch (algo) + { + case PUBKEY_ALGO_EDDSA: return GCRY_PK_EDDSA; + case PUBKEY_ALGO_ECDSA: return GCRY_PK_ECDSA; + case PUBKEY_ALGO_ECDH: return GCRY_PK_ECDH; + default: return algo < 110 ? (enum gcry_pk_algos)algo : 0; + } +} + + +/* Return a string describing the public key algorithm and the + * keysize. For elliptic curves the function prints the name of the + * curve because the keysize is a property of the curve. ALGO is the + * Gcrypt algorithmj number, curve is either NULL or give the PID of + * the curve, NBITS is either 0 or the size of the algorithms for RSA + * etc. The returned string is taken from permanent table. Examples + * for the output are: + * + * "rsa3072" - RSA with 3072 bit + * "elg1024" - Elgamal with 1024 bit + * "ed25519" - ECC using the curve Ed25519. + * "E_1.2.3.4" - ECC using the unsupported curve with OID "1.2.3.4". + * "E_1.3.6.1.4.1.11591.2.12242973" - ECC with a bogus OID. + * "unknown_N" - Unknown OpenPGP algorithm N. + * If N is > 110 this is a gcrypt algo. + */ +const char * +get_keyalgo_string (enum gcry_pk_algos algo, + unsigned int nbits, const char *curve) +{ + const char *prefix; + int i; + char *name, *curvebuf; + + switch (algo) + { + case GCRY_PK_RSA: prefix = "rsa"; break; + case GCRY_PK_ELG: prefix = "elg"; break; + case GCRY_PK_DSA: prefix = "dsa"; break; + case GCRY_PK_ECC: + case GCRY_PK_ECDH: + case GCRY_PK_ECDSA: + case GCRY_PK_EDDSA: prefix = ""; break; + default: prefix = NULL; break; + } + + if (prefix && *prefix && nbits) + { + for (i=0; i < keyalgo_strings_used; i++) + { + if (keyalgo_strings[i].algo == algo + && keyalgo_strings[i].nbits + && keyalgo_strings[i].nbits == nbits) + return keyalgo_strings[i].name; + } + /* Not yet in the table - add it. */ + name = xasprintf ("%s%u", prefix, nbits); + nbits = nbits? nbits : 1; /* No nbits - oops - use 1 instead. */ + curvebuf = NULL; + } + else if (prefix && !*prefix) + { + const char *curvename; + + for (i=0; i < keyalgo_strings_used; i++) + { + if (keyalgo_strings[i].algo == algo + && keyalgo_strings[i].curve + && !strcmp (keyalgo_strings[i].curve, curve)) + return keyalgo_strings[i].name; + } + + /* Not yet in the table - add it. */ + curvename = openpgp_oid_or_name_to_curve (curve, 0); + if (curvename) + name = xasprintf ("%s", curvename); + else if (curve) + name = xasprintf ("E_%s", curve); + else + name = xasprintf ("E_error"); + nbits = 0; + curvebuf = xstrdup (curve); + } + else + { + for (i=0; i < keyalgo_strings_used; i++) + { + if (keyalgo_strings[i].algo == algo + && !keyalgo_strings[i].nbits + && !keyalgo_strings[i].curve) + return keyalgo_strings[i].name; + } + /* Not yet in the table - add it. */ + name = xasprintf ("unknown_%u", (unsigned int)algo); + nbits = 0; + curvebuf = NULL; + } + + /* Store a new entry. This is a loop because of a possible nPth + * thread switch during xrealloc. */ + while (keyalgo_strings_used >= keyalgo_strings_size) + { + keyalgo_strings_size += 10; + if (keyalgo_strings_size > 1024*1024) + log_fatal ("%s: table getting too large - possible DoS\n", __func__); + keyalgo_strings = xrealloc (keyalgo_strings, (keyalgo_strings_size + * sizeof *keyalgo_strings)); + } + keyalgo_strings[keyalgo_strings_used].algo = algo; + keyalgo_strings[keyalgo_strings_used].nbits = nbits; + keyalgo_strings[keyalgo_strings_used].curve = curvebuf; + keyalgo_strings[keyalgo_strings_used].name = name; + keyalgo_strings_used++; + + return name; /* Note that this is in the table. */ +} diff --git a/common/t-openpgp-oid.c b/common/t-openpgp-oid.c index fd9de5dde..56fb6fefe 100644 --- a/common/t-openpgp-oid.c +++ b/common/t-openpgp-oid.c @@ -27,7 +27,7 @@ #define pass() do { ; } while(0) #define fail(a,e) \ do { fprintf (stderr, "%s:%d: test %d failed (%s)\n", \ - __FILE__,__LINE__, (a), gpg_strerror (e)); \ + __func__, __LINE__, (a), gpg_strerror (e)); \ exit (1); \ } while(0) @@ -150,7 +150,7 @@ test_openpgp_oid_to_str (void) if (strcmp (string, samples[idx].string)) fail (idx, 0); xfree (string); -} + } } @@ -226,6 +226,74 @@ test_openpgp_enum_curves (void) } +static void +test_get_keyalgo_string (void) +{ + static struct + { + int algo; + unsigned int nbits; + const char *curve; + const char *name; + } samples[] = + { + { GCRY_PK_RSA, 1024, NULL, "rsa1024" }, + { GCRY_PK_RSA, 1536, NULL, "rsa1536" }, + { GCRY_PK_RSA, 768, NULL, "rsa768" }, + { GCRY_PK_DSA, 3072, NULL, "dsa3072" }, + { GCRY_PK_DSA, 1024, NULL, "dsa1024" }, + { GCRY_PK_ELG, 2048, NULL, "elg2048" }, + { GCRY_PK_ELG, 0, NULL, "unknown_20" }, + { 47114711, 1000, NULL, "unknown_47114711" }, + /* Note that we don't care about the actual ECC algorithm. */ + { GCRY_PK_EDDSA, 0, "1.3.6.1.4.1.11591.15.1", "ed25519" }, + { GCRY_PK_ECDSA, 0, "1.3.6.1.4.1.11591.15.1", "ed25519" }, + { GCRY_PK_ECDH, 0, "1.3.6.1.4.1.11591.15.1", "ed25519" }, + { GCRY_PK_ECDH, 0, "1.3.6.1.4.1.3029.1.5.1", "cv25519" }, + { GCRY_PK_ECDH, 0, "1.3.36.3.3.2.8.1.1.7", "brainpoolP256r1" }, + { GCRY_PK_ECDH, 0, "1.3.36.3.3.2.8.1.1.11", "brainpoolP384r1" }, + { GCRY_PK_ECDH, 0, "1.3.36.3.3.2.8.1.1.13", "brainpoolP512r1" }, + { GCRY_PK_ECDH, 0, "1.3.132.0.10", "secp256k1" }, + { GCRY_PK_ECDH, 0, "1.2.840.10045.3.1.7", "nistp256" }, + { GCRY_PK_ECDH, 0, "1.3.132.0.34", "nistp384" }, + { GCRY_PK_ECDH, 0, "1.3.132.0.35", "nistp521" }, + { GCRY_PK_ECDH, 0, "1.2.3.4.5.6", "E_1.2.3.4.5.6" }, + { GCRY_PK_ECDH, 0, BADOID, "E_1.3.6.1.4.1.11591.2.12242973" }, + + /* Some again to test existing lookups. */ + { GCRY_PK_RSA, 768, NULL, "rsa768" }, + { GCRY_PK_DSA, 3072, NULL, "dsa3072" }, + { GCRY_PK_DSA, 1024, NULL, "dsa1024" }, + { GCRY_PK_ECDH, 0, "1.3.6.1.4.1.11591.15.1", "ed25519" }, + { GCRY_PK_ECDH, 0, "1.3.6.1.4.1.3029.1.5.1", "cv25519" }, + { GCRY_PK_ECDH, 0, "1.3.36.3.3.2.8.1.1.7", "brainpoolP256r1" }, + { 47114711, 1000, NULL, "unknown_47114711" } + }; + int idx; + const char *name; + int oops = 0; + int pass; + + /* We do several passes becuase that is how the function is + * called. */ + for (pass=0; pass < 3; pass++) + for (idx=0; idx < DIM (samples); idx++) + { + name = get_keyalgo_string (samples[idx].algo, + samples[idx].nbits, + samples[idx].curve); + if (strcmp (samples[idx].name, name)) + { + fprintf (stderr, "%s:test %d.%d: want '%s' got '%s'\n", + __func__, pass, idx, samples[idx].name, name); + oops = 1; + } + } + if (oops) + exit (1); +} + + int main (int argc, char **argv) { @@ -241,6 +309,7 @@ main (int argc, char **argv) test_openpgp_oid_to_str (); test_openpgp_oid_is_ed25519 (); test_openpgp_enum_curves (); + test_get_keyalgo_string (); return 0; } diff --git a/common/util.h b/common/util.h index 82b3a34af..cd961d212 100644 --- a/common/util.h +++ b/common/util.h @@ -248,9 +248,12 @@ int openpgp_oid_is_cv25519 (gcry_mpi_t a); const char *openpgp_curve_to_oid (const char *name, unsigned int *r_nbits, int *r_algo); const char *openpgp_oid_to_curve (const char *oid, int canon); +const char *openpgp_oid_or_name_to_curve (const char *oidname, int canon); const char *openpgp_enum_curves (int *idxp); const char *openpgp_is_curve_supported (const char *name, int *r_algo, unsigned int *r_nbits); +const char *get_keyalgo_string (enum gcry_pk_algos algo, + unsigned int nbits, const char *curve); /*-- homedir.c --*/ diff --git a/g10/keyid.c b/g10/keyid.c index 69d85da0f..1b374dde4 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -88,7 +88,10 @@ pubkey_letter( int algo ) "256E" - ECDSA using a curve with 256 bit The macro PUBKEY_STRING_SIZE may be used to allocate a buffer with - a suitable size.*/ + a suitable size. Note that a more general version of this function + exists as get_keyalgo_string. However, that has no special + treatment for the old and unsupported Elgamal which we here print as + xxxNNNN. */ char * pubkey_string (PKT_public_key *pk, char *buffer, size_t bufsize) { |