1 /* openpgp-oids.c - OID helper for OpenPGP
2 * Copyright (C) 2011 Free Software Foundation, Inc.
3 * Copyright (C) 2013 Werner Koch
5 * This file is part of GnuPG.
7 * This file is free software; you can redistribute it and/or modify
8 * it under the terms of either
10 * - the GNU Lesser General Public License as published by the Free
11 * Software Foundation; either version 3 of the License, or (at
12 * your option) any later version.
16 * - the GNU General Public License as published by the Free
17 * Software Foundation; either version 2 of the License, or (at
18 * your option) any later version.
20 * or both in parallel, as here.
22 * This file is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, see <http://www.gnu.org/licenses/>.
40 /* A table with all our supported OpenPGP curves. */
42 const char *name; /* Standard name. */
43 const char *oidstr; /* IETF formatted OID. */
44 unsigned int nbits; /* Nominal bit length of the curve. */
45 const char *alias; /* NULL or alternative name of the curve. */
48 { "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519" },
49 { "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519" },
51 { "NIST P-256", "1.2.840.10045.3.1.7", 256, "nistp256" },
52 { "NIST P-384", "1.3.132.0.34", 384, "nistp384" },
53 { "NIST P-521", "1.3.132.0.35", 521, "nistp521" },
55 { "brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7", 256 },
56 { "brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11", 384 },
57 { "brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", 512 },
59 { "secp256k1", "1.3.132.0.10", 256 },
65 /* The OID for Curve Ed25519 in OpenPGP format. */
66 static const char oid_ed25519[] =
67 { 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01 };
69 /* The OID for Curve25519 in OpenPGP format. */
70 static const char oid_crv25519[] =
71 { 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01 };
74 /* Helper for openpgp_oid_from_str. */
76 make_flagged_int (unsigned long value, char *buf, size_t buflen)
81 /* fixme: figure out the number of bits in an ulong and start with
82 that value as shift (after making it a multiple of 7) a more
83 straigtforward implementation is to do it in reverse order using
84 a temporary buffer - saves a lot of compares */
85 for (more=0, shift=28; shift > 0; shift -= 7)
87 if (more || value >= (1<<shift))
89 buf[buflen++] = 0x80 | (value >> shift);
90 value -= (value >> shift) << shift;
94 buf[buflen++] = value;
99 /* Convert the OID given in dotted decimal form in STRING to an DER
100 * encoding and store it as an opaque value at R_MPI. The format of
101 * the DER encoded is not a regular ASN.1 object but the modified
102 * format as used by OpenPGP for the ECC curve description. On error
103 * the function returns and error code an NULL is stored at R_BUG.
104 * Note that scanning STRING stops at the first white space
107 openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi)
111 unsigned long val1, val;
117 if (!string || !*string)
118 return gpg_error (GPG_ERR_INV_VALUE);
120 /* We can safely assume that the encoded OID is shorter than the string. */
121 buf = xtrymalloc (1 + strlen (string) + 2);
123 return gpg_error_from_syserror ();
124 /* Save the first byte for the length. */
127 val1 = 0; /* Avoid compiler warning. */
131 val = strtoul (string, (char**)&endp, 10);
132 if (!digitp (string) || !(*endp == '.' || !*endp))
135 return gpg_error (GPG_ERR_INV_OID_STRING);
143 break; /* Not allowed, error catched below. */
147 { /* Need to combine the first two arcs in one octet. */
153 return gpg_error (GPG_ERR_INV_OID_STRING);
155 buf[buflen++] = val1*40 + val;
160 buflen = make_flagged_int (val, buf, buflen);
165 buflen = make_flagged_int (val, buf, buflen);
167 } while (*endp == '.');
169 if (arcno == 1 || buflen < 2 || buflen > 254 )
170 { /* It is not possible to encode only the first arc. */
172 return gpg_error (GPG_ERR_INV_OID_STRING);
176 *r_mpi = gcry_mpi_set_opaque (NULL, buf, buflen * 8);
180 return gpg_error_from_syserror ();
186 /* Return a malloced string represenation of the OID in the opaque MPI
187 A. In case of an error NULL is returned and ERRNO is set. */
189 openpgp_oid_to_str (gcry_mpi_t a)
191 const unsigned char *buf;
193 unsigned int lengthi;
196 unsigned long val, valmask;
198 valmask = (unsigned long)0xfe << (8 * (sizeof (valmask) - 1));
201 || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)
202 || !(buf = gcry_mpi_get_opaque (a, &lengthi)))
204 gpg_err_set_errno (EINVAL);
208 buf = gcry_mpi_get_opaque (a, &lengthi);
209 length = (lengthi+7)/8;
211 /* The first bytes gives the length; check consistency. */
212 if (!length || buf[0] != length -1)
214 gpg_err_set_errno (EINVAL);
217 /* Skip length byte. */
221 /* To calculate the length of the string we can safely assume an
222 upper limit of 3 decimal characters per byte. Two extra bytes
223 account for the special first octect */
224 string = p = xtrymalloc (length*(1+3)+2+1);
234 p += sprintf (p, "0.%d", buf[n]);
235 else if (buf[0] < 80)
236 p += sprintf (p, "1.%d", buf[n]-40);
239 while ( (buf[n]&0x80) && ++n < length )
241 if ( (val & valmask) )
242 goto badoid; /* Overflow. */
244 val |= buf[n] & 0x7f;
249 sprintf (p, "2.%lu", val);
252 for (n++; n < length; n++)
255 while ( (buf[n]&0x80) && ++n < length )
257 if ( (val & valmask) )
258 goto badoid; /* Overflow. */
260 val |= buf[n] & 0x7f;
262 sprintf (p, ".%lu", val);
270 /* Return a special OID (gnu.gnupg.badoid) to indicate the error
271 case. The OID is broken and thus we return one which can't do
272 any harm. Formally this does not need to be a bad OID but an OID
273 with an arc that can't be represented in a 32 bit word is more
274 than likely corrupt. */
276 return xtrystrdup ("1.3.6.1.4.1.11591.2.12242973");
281 /* Return true if A represents the OID for Ed25519. */
283 openpgp_oid_is_ed25519 (gcry_mpi_t a)
285 const unsigned char *buf;
289 if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
292 buf = gcry_mpi_get_opaque (a, &nbits);
294 return (n == DIM (oid_ed25519)
295 && !memcmp (buf, oid_ed25519, DIM (oid_ed25519)));
300 openpgp_oid_is_crv25519 (gcry_mpi_t a)
302 const unsigned char *buf;
306 if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
309 buf = gcry_mpi_get_opaque (a, &nbits);
311 return (n == DIM (oid_crv25519)
312 && !memcmp (buf, oid_crv25519, DIM (oid_crv25519)));
316 /* Map the Libgcrypt ECC curve NAME to an OID. If R_NBITS is not NULL
317 store the bit size of the curve there. Returns NULL for unknown
320 openpgp_curve_to_oid (const char *name, unsigned int *r_nbits)
323 unsigned int nbits = 0;
324 const char *oidstr = NULL;
328 for (i=0; oidtable[i].name; i++)
329 if (!strcmp (oidtable[i].name, name)
330 || (oidtable[i].alias && !strcmp (oidtable[i].alias, name)))
332 oidstr = oidtable[i].oidstr;
333 nbits = oidtable[i].nbits;
336 if (!oidtable[i].name)
338 /* If not found assume the input is already an OID and check
339 whether we support it. */
340 for (i=0; oidtable[i].name; i++)
341 if (!strcmp (name, oidtable[i].oidstr))
343 oidstr = oidtable[i].oidstr;
344 nbits = oidtable[i].nbits;
356 /* Map an OpenPGP OID to the Libgcrypt curve NAME. Returns NULL for
357 unknown curve names. Unless CANON is set we prefer an alias name
358 here which is more suitable for printing. */
360 openpgp_oid_to_curve (const char *oidstr, int canon)
367 for (i=0; oidtable[i].name; i++)
368 if (!strcmp (oidtable[i].oidstr, oidstr))
369 return !canon && oidtable[i].alias? oidtable[i].alias : oidtable[i].name;
375 /* Return true if the curve with NAME is supported. */
377 curve_supported_p (const char *name)
380 gcry_sexp_t keyparms;
382 if (!gcry_sexp_build (&keyparms, NULL, "(public-key(ecc(curve %s)))", name))
384 result = !!gcry_pk_get_curve (keyparms, 0, NULL);
385 gcry_sexp_release (keyparms);
391 /* Enumerate available and supported OpenPGP curves. The caller needs
392 to set the integer variable at ITERP to zero and keep on calling
393 this fucntion until NULL is returned. */
395 openpgp_enum_curves (int *iterp)
399 while (idx >= 0 && idx < DIM (oidtable) && oidtable[idx].name)
401 if (curve_supported_p (oidtable[idx].name))
404 return oidtable[idx].alias? oidtable[idx].alias : oidtable[idx].name;