aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2020-02-09 20:20:48 +0000
committerWerner Koch <[email protected]>2020-02-09 20:26:35 +0000
commit3a1fa13eedb969b561bae18cd3d7c2fb0b63d6ab (patch)
tree704e4441d3a713a82dd587e94c6874cd1615f87e
parentcommon: Add OpenPGP<->Gcrypt pubkey id mapping functions. (diff)
downloadgnupg-3a1fa13eedb969b561bae18cd3d7c2fb0b63d6ab.tar.gz
gnupg-3a1fa13eedb969b561bae18cd3d7c2fb0b63d6ab.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. (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]>
-rw-r--r--common/openpgp-oid.c121
-rw-r--r--common/t-openpgp-oid.c73
-rw-r--r--common/util.h2
-rw-r--r--g10/keyid.c5
4 files changed, 198 insertions, 3 deletions
diff --git a/common/openpgp-oid.c b/common/openpgp-oid.c
index 802d71162..b539f8588 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
@@ -492,3 +507,109 @@ map_openpgp_pk_to_gcry (pubkey_algo_t algo)
default: return algo < 110 ? 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 = NULL;
+ 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_ECDH:
+ case GCRY_PK_ECDSA:
+ case GCRY_PK_EDDSA: prefix = ""; 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_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 fc869800a..9d73412c3 100644
--- a/common/util.h
+++ b/common/util.h
@@ -235,6 +235,8 @@ const char *openpgp_oid_to_curve (const char *oid, 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 a7a54e07b..e6298e5da 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)
{