summaryrefslogtreecommitdiff
path: root/src/keyinfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/keyinfo.c')
-rw-r--r--src/keyinfo.c1285
1 files changed, 576 insertions, 709 deletions
diff --git a/src/keyinfo.c b/src/keyinfo.c
index 265b475..666726f 100644
--- a/src/keyinfo.c
+++ b/src/keyinfo.c
@@ -1,5 +1,5 @@
/* keyinfo.c - Parse and build a keyInfo structure
- * Copyright (C) 2001, 2002, 2007, 2008, 2012 g10 Code GmbH
+ * Copyright (C) 2001, 2002, 2007, 2008, 2012, 2020 g10 Code GmbH
*
* This file is part of KSBA.
*
@@ -44,14 +44,21 @@
#include "shared.h"
#include "convert.h"
#include "ber-help.h"
-
+#include "sexp-parse.h"
+#include "stringbuf.h"
+#include "der-builder.h"
/* Constants used for the public key algorithms. */
typedef enum
{
+ PKALGO_NONE,
PKALGO_RSA,
PKALGO_DSA,
- PKALGO_ECC
+ PKALGO_ECC,
+ PKALGO_X25519,
+ PKALGO_X448,
+ PKALGO_ED25519,
+ PKALGO_ED448
}
pkalgo_t;
@@ -60,7 +67,7 @@ struct algo_table_s {
const char *oidstring;
const unsigned char *oid; /* NULL indicattes end of table */
int oidlen;
- int supported;
+ int supported; /* Values > 1 are also used to indicate hacks. */
pkalgo_t pkalgo;
const char *algo_string;
const char *elem_string; /* parameter name or '-' */
@@ -70,6 +77,8 @@ struct algo_table_s {
const char *digest_string; /* The digest algo if included in the OID. */
};
+/* Special values for the supported field. */
+#define SUPPORTED_RSAPSS 2
static const struct algo_table_s pk_algo_table[] = {
@@ -82,7 +91,12 @@ static const struct algo_table_s pk_algo_table[] = {
{ /* iso.member-body.us.rsadsi.pkcs.pkcs-1.7 */
"1.2.840.113549.1.1.7", /* RSAES-OAEP */
"\x2a\x86\x48\x86\xf7\x0d\x01\x01\x07", 9,
- 0, PKALGO_RSA, "rsa", "-ne", "\x30\x02\x02"}, /* (patent problems) */
+ 0, PKALGO_RSA, "rsa", "-ne", "\x30\x02\x02"},
+
+ { /* iso.member-body.us.rsadsi.pkcs.pkcs-1.10 */
+ "1.2.840.113549.1.1.10", /* rsaPSS */
+ "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0a", 9,
+ SUPPORTED_RSAPSS, PKALGO_RSA, "rsa", "-ne", "\x30\x02\x02"},
{ /* */
"2.5.8.1.1", /* rsa (ambiguous due to missing padding rules)*/
@@ -99,6 +113,26 @@ static const struct algo_table_s pk_algo_table[] = {
"\x2a\x86\x48\xce\x3d\x02\x01", 7,
1, PKALGO_ECC, "ecc", "q", "\x80" },
+ { /* iso.identified-organization.thawte.110 */
+ "1.3.101.110", /* X25519 */
+ "\x2b\x65\x6e", 3,
+ 1, PKALGO_X25519, "ecc", "q", "\x80" },
+
+ { /* iso.identified-organization.thawte.111 */
+ "1.3.101.111", /* X448 */
+ "\x2b\x65\x6f", 3,
+ 1, PKALGO_X448, "ecc", "q", "\x80" },
+
+ { /* iso.identified-organization.thawte.112 */
+ "1.3.101.112", /* Ed25519 */
+ "\x2b\x65\x70", 3,
+ 1, PKALGO_ED25519, "ecc", "q", "\x80" },
+
+ { /* iso.identified-organization.thawte.113 */
+ "1.3.101.113", /* Ed448 */
+ "\x2b\x65\x71", 3,
+ 1, PKALGO_ED448, "ecc", "q", "\x80" },
+
{NULL}
};
@@ -203,6 +237,11 @@ static const struct algo_table_s sig_algo_table[] = {
"\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0d", 9,
1, PKALGO_RSA, "rsa", "s", "\x82", NULL, NULL, "sha512" },
+ { /* iso.member-body.us.rsadsi.pkcs.pkcs-1.10 */
+ "1.2.840.113549.1.1.10", /* rsaPSS */
+ "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0a", 9,
+ SUPPORTED_RSAPSS, PKALGO_RSA, "rsa", "s", "\x82", NULL, NULL, NULL},
+
{ /* TeleTrust signature scheme with RSA signature and DSI according
to ISO/IEC 9796-2 with random number and RIPEMD-160. I am not
sure for what this is good; thus disabled. */
@@ -210,28 +249,47 @@ static const struct algo_table_s sig_algo_table[] = {
"\x2B\x24\x03\x04\x03\x02\x02", 7,
0, PKALGO_RSA, "rsa", "s", "\x82", NULL, NULL, "rmd160" },
+
+ { /* iso.identified-organization.thawte.112 */
+ "1.3.101.112", /* Ed25519 */
+ "\x2b\x65\x70", 3,
+ 1, PKALGO_ED25519, "eddsa", "", "", NULL, NULL, NULL },
+ { /* iso.identified-organization.thawte.113 */
+ "1.3.101.113", /* Ed448 */
+ "\x2b\x65\x71", 3,
+ 1, PKALGO_ED448, "eddsa", "", "", NULL, NULL, NULL },
+
{NULL}
};
static const struct algo_table_s enc_algo_table[] = {
- { /* iso.member-body.us.rsadsi.pkcs.pkcs-1.1 */
- "1.2.840.113549.1.1.1", /* rsaEncryption (RSAES-PKCA1-v1.5) */
- "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01", 9,
- 1, PKALGO_RSA, "rsa", "a", "\x82" },
+ {/* iso.member-body.us.rsadsi.pkcs.pkcs-1.1 */
+ "1.2.840.113549.1.1.1", /* rsaEncryption (RSAES-PKCA1-v1.5) */
+ "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01", 9,
+ 1, PKALGO_RSA, "rsa", "a", "\x82" },
+ {/* iso.member-body.us.ansi-x9-62.2.1 */
+ "1.2.840.10045.2.1", /* ecPublicKey */
+ "\x2a\x86\x48\xce\x3d\x02\x01", 7,
+ 1, PKALGO_ECC, "ecdh", "e", "\x80" },
{NULL}
};
/* This tables maps names of ECC curves names to OIDs. A similar
- table is used by lib gcrypt. */
+ table is used by Libgcrypt. */
static const struct
{
const char *oid;
const char *name;
+ unsigned char pkalgo; /* If not 0 force the use of ALGO. */
} curve_names[] =
{
- { "1.3.6.1.4.1.3029.1.5.1", "Curve25519" },
- { "1.3.6.1.4.1.11591.15.1", "Ed25519" },
+ { "1.3.101.112", "Ed25519", PKALGO_ED25519},
+ { "1.3.101.110", "Curve25519", PKALGO_X25519},
+ { "1.3.101.110", "X25519", PKALGO_X25519},
+
+ { "1.3.101.113", "Ed448", PKALGO_ED448 },
+ { "1.3.101.111", "X448", PKALGO_X448 },
{ "1.2.840.10045.3.1.1", "NIST P-192" },
{ "1.2.840.10045.3.1.1", "nistp192" },
@@ -277,16 +335,6 @@ static const struct
-
-
-struct stringbuf {
- size_t len;
- size_t size;
- char *buf;
- int out_of_core;
-};
-
-
#define TLV_LENGTH(prefix) do { \
if (!prefix ## len) \
return gpg_error (GPG_ERR_INV_KEYINFO); \
@@ -316,13 +364,16 @@ struct stringbuf {
} while (0)
-/* Given a string BUF of length BUFLEN with either the name of an ECC
- curve or its OID in dotted form return the DER encoding of the OID.
- The caller must free the result. On error NULL is returned. */
-static unsigned char *
-get_ecc_curve_oid (const unsigned char *buf, size_t buflen, size_t *r_oidlen)
+/* Given a string BUF of length BUFLEN with either a curve name or its
+ * OID in dotted form return a string in dotted form of the name. The
+ * caller must free the result. On error NULL is returned. If a
+ * curve requires the use of a certain algorithm, that algorithm is
+ * stored at R_PKALGO. */
+static char *
+get_ecc_curve_oid (const unsigned char *buf, size_t buflen, pkalgo_t *r_pkalgo)
{
- unsigned char *der_oid;
+ unsigned char *result;
+ int i, find_pkalgo;
/* Skip an optional "oid." prefix. */
if (buflen > 4 && buf[3] == '.' && digitp (buf+4)
@@ -336,8 +387,6 @@ get_ecc_curve_oid (const unsigned char *buf, size_t buflen, size_t *r_oidlen)
/* If it does not look like an OID - map it through the table. */
if (buflen && !digitp (buf))
{
- int i;
-
for (i=0; curve_names[i].oid; i++)
if (buflen == strlen (curve_names[i].name)
&& !memcmp (buf, curve_names[i].name, buflen))
@@ -346,11 +395,30 @@ get_ecc_curve_oid (const unsigned char *buf, size_t buflen, size_t *r_oidlen)
return NULL; /* Not found. */
buf = curve_names[i].oid;
buflen = strlen (curve_names[i].oid);
+ *r_pkalgo = curve_names[i].pkalgo;
+ find_pkalgo = 0;
}
+ else
+ find_pkalgo = 1;
- if (_ksba_oid_from_buf (buf, buflen, &der_oid, r_oidlen))
- return NULL;
- return der_oid;
+ result = xtrymalloc (buflen + 1);
+ if (!result)
+ return NULL; /* Ooops */
+ memcpy (result, buf, buflen);
+ result[buflen] = 0;
+
+ if (find_pkalgo)
+ {
+ /* We still need to check whether the OID requires a certain ALGO. */
+ for (i=0; curve_names[i].oid; i++)
+ if (!strcmp (curve_names[i].oid, result))
+ {
+ *r_pkalgo = curve_names[i].pkalgo;
+ break;
+ }
+ }
+
+ return result;
}
@@ -401,11 +469,6 @@ get_algorithm (int mode, const unsigned char *der, size_t derlen,
/* der does now point to an oid of length LEN */
*r_pos = der - start;
*r_len = len;
-/* { */
-/* char *p = ksba_oid_to_str (der, len); */
-/* printf ("algorithm: %s\n", p); */
-/* xfree (p); */
-/* } */
der += len;
derlen -= len;
seqlen -= der - startseq;;
@@ -420,7 +483,7 @@ get_algorithm (int mode, const unsigned char *der, size_t derlen,
c = *der++; derlen--;
if ( c == 0x05 )
{
- /*printf ("parameter: NULL \n"); the usual case */
+ /* gpgrt_log_debug ("%s: parameter: NULL \n", __func__); */
if (!derlen)
return gpg_error (GPG_ERR_INV_KEYINFO);
c = *der++; derlen--;
@@ -512,6 +575,8 @@ _ksba_parse_algorithm_identifier (const unsigned char *der, size_t derlen,
r_nread, r_oid, NULL, NULL);
}
+
+/* Note that R_NREAD, R_PARM, and R_PARMLEN are optional. */
gpg_error_t
_ksba_parse_algorithm_identifier2 (const unsigned char *der, size_t derlen,
size_t *r_nread, char **r_oid,
@@ -525,13 +590,15 @@ _ksba_parse_algorithm_identifier2 (const unsigned char *der, size_t derlen,
/* fixme: get_algorithm might return the error invalid keyinfo -
this should be invalid algorithm identifier */
*r_oid = NULL;
- *r_nread = 0;
+ if (r_nread)
+ *r_nread = 0;
off2 = len2 = 0;
err = get_algorithm (0, der, derlen, &nread, &off, &len, &is_bitstr,
&off2, &len2, &parm_type);
if (err)
return err;
- *r_nread = nread;
+ if (r_nread)
+ *r_nread = nread;
*r_oid = ksba_oid_to_str (der+off, len);
if (!*r_oid)
return gpg_error (GPG_ERR_ENOMEM);
@@ -547,13 +614,15 @@ _ksba_parse_algorithm_identifier2 (const unsigned char *der, size_t derlen,
NULL, NULL, NULL);
if (err)
{
- *r_nread = 0;
+ if (r_nread)
+ *r_nread = 0;
return err;
}
*r_oid = ksba_oid_to_str (der+off2+off, len);
if (!*r_oid)
{
- *r_nread = 0;
+ if (r_nread)
+ *r_nread = 0;
return gpg_error (GPG_ERR_ENOMEM);
}
@@ -585,84 +654,8 @@ _ksba_parse_algorithm_identifier2 (const unsigned char *der, size_t derlen,
-static void
-init_stringbuf (struct stringbuf *sb, int initiallen)
-{
- sb->len = 0;
- sb->size = initiallen;
- sb->out_of_core = 0;
- /* allocate one more, so that get_stringbuf can append a nul */
- sb->buf = xtrymalloc (initiallen+1);
- if (!sb->buf)
- sb->out_of_core = 1;
-}
-
-static void
-put_stringbuf_mem (struct stringbuf *sb, const char *text, size_t n)
-{
- if (sb->out_of_core)
- return;
-
- if (sb->len + n >= sb->size)
- {
- char *p;
-
- sb->size += n + 100;
- p = xtryrealloc (sb->buf, sb->size);
- if ( !p)
- {
- sb->out_of_core = 1;
- return;
- }
- sb->buf = p;
- }
- memcpy (sb->buf+sb->len, text, n);
- sb->len += n;
-}
-
-static void
-put_stringbuf (struct stringbuf *sb, const char *text)
-{
- put_stringbuf_mem (sb, text,strlen (text));
-}
-
-static void
-put_stringbuf_mem_sexp (struct stringbuf *sb, const char *text, size_t length)
-{
- char buf[20];
- sprintf (buf,"%u:", (unsigned int)length);
- put_stringbuf (sb, buf);
- put_stringbuf_mem (sb, text, length);
-}
-
-static void
-put_stringbuf_sexp (struct stringbuf *sb, const char *text)
-{
- put_stringbuf_mem_sexp (sb, text, strlen (text));
-}
-
-
-static char *
-get_stringbuf (struct stringbuf *sb)
-{
- char *p;
-
- if (sb->out_of_core)
- {
- xfree (sb->buf); sb->buf = NULL;
- return NULL;
- }
-
- sb->buf[sb->len] = 0;
- p = sb->buf;
- sb->buf = NULL;
- sb->out_of_core = 1; /* make sure the caller does an init before reuse */
- return p;
-}
-
-
/* Assume that der is a buffer of length DERLEN with a DER encoded
- Asn.1 structure like this:
+ ASN.1 structure like this:
keyInfo ::= SEQUENCE {
SEQUENCE {
@@ -763,6 +756,16 @@ _ksba_keyinfo_to_sexp (const unsigned char *der, size_t derlen,
put_stringbuf_sexp (&sb, parm_oid);
put_stringbuf (&sb, ")");
}
+ else if (pk_algo_table[algoidx].pkalgo == PKALGO_ED25519
+ || pk_algo_table[algoidx].pkalgo == PKALGO_ED448
+ || pk_algo_table[algoidx].pkalgo == PKALGO_X25519
+ || pk_algo_table[algoidx].pkalgo == PKALGO_X448)
+ {
+ put_stringbuf (&sb, "(");
+ put_stringbuf_sexp (&sb, "curve");
+ put_stringbuf_sexp (&sb, pk_algo_table[algoidx].oidstring);
+ put_stringbuf (&sb, ")");
+ }
/* If parameters are given and we have a description for them, parse
them. */
@@ -869,11 +872,11 @@ _ksba_keyinfo_to_sexp (const unsigned char *der, size_t derlen,
/* Match the algorithm string given in BUF which is of length BUFLEN
- with the known algorithms from our table and returns the table
- entries for the DER encoded OID. If WITH_SIG is true, the table of
- signature algorithms is consulted first. */
-static const unsigned char *
-oid_from_buffer (const unsigned char *buf, int buflen, int *oidlen,
+ * with the known algorithms from our table and return the table
+ * entriy with the OID string. If WITH_SIG is true, the table of
+ * signature algorithms is consulted first. */
+static const char *
+oid_from_buffer (const unsigned char *buf, unsigned int buflen,
pkalgo_t *r_pkalgo, int with_sig)
{
int i;
@@ -904,8 +907,7 @@ oid_from_buffer (const unsigned char *buf, int buflen, int *oidlen,
if (sig_algo_table[i].oid)
{
*r_pkalgo = sig_algo_table[i].pkalgo;
- *oidlen = sig_algo_table[i].oidlen;
- return sig_algo_table[i].oid;
+ return sig_algo_table[i].oidstring;
}
}
@@ -925,26 +927,26 @@ oid_from_buffer (const unsigned char *buf, int buflen, int *oidlen,
return NULL;
*r_pkalgo = pk_algo_table[i].pkalgo;
- *oidlen = pk_algo_table[i].oidlen;
- return pk_algo_table[i].oid;
+ return pk_algo_table[i].oidstring;
}
-/* Take a public-key S-Exp and convert it into a DER encoded
- publicKeyInfo */
+/* If ALGOINFOMODE is false: Take the "public-key" s-expression SEXP
+ * and convert it into a DER encoded publicKeyInfo.
+ *
+ * If ALGOINFOMODE is true: Take the "sig-val" s-expression SEXP and
+ * convert it into a DER encoded algorithmInfo. */
gpg_error_t
-_ksba_keyinfo_from_sexp (ksba_const_sexp_t sexp,
+_ksba_keyinfo_from_sexp (ksba_const_sexp_t sexp, int algoinfomode,
unsigned char **r_der, size_t *r_derlen)
{
gpg_error_t err;
const unsigned char *s;
char *endp;
- unsigned long n, n1;
- const unsigned char *oid;
- int oidlen;
- unsigned char *curve_oid = NULL;
- size_t curve_oidlen;
- pkalgo_t pkalgo;
+ unsigned long n;
+ const char *algo_oid;
+ char *curve_oid = NULL;
+ pkalgo_t pkalgo, force_pkalgo;
int i;
struct {
const char *name;
@@ -953,14 +955,11 @@ _ksba_keyinfo_from_sexp (ksba_const_sexp_t sexp,
int valuelen;
} parm[10];
int parmidx;
- int idxtbl[10];
- int idxtbllen;
const char *parmdesc, *algoparmdesc;
- ksba_writer_t writer = NULL;
- void *algoparmseq_value = NULL;
- size_t algoparmseq_len;
- void *bitstr_value = NULL;
- size_t bitstr_len;
+ ksba_der_t dbld = NULL;
+ ksba_der_t dbld2 = NULL;
+ unsigned char *tmpder;
+ size_t tmpderlen;
if (!sexp)
return gpg_error (GPG_ERR_INV_VALUE);
@@ -973,11 +972,16 @@ _ksba_keyinfo_from_sexp (ksba_const_sexp_t sexp,
n = strtoul (s, &endp, 10);
s = endp;
if (!n || *s != ':')
- return gpg_error (GPG_ERR_INV_SEXP); /* we don't allow empty lengths */
+ return gpg_error (GPG_ERR_INV_SEXP); /* We don't allow empty lengths. */
s++;
- if (n != 10 || memcmp (s, "public-key", 10))
+
+ if (algoinfomode && n == 7 && !memcmp (s, "sig-val", 7))
+ s += 7;
+ else if (n == 10 || !memcmp (s, "public-key", 10))
+ s += 10;
+ else
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- s += 10;
+
if (*s != '(')
return gpg_error (digitp (s)? GPG_ERR_UNKNOWN_SEXP : GPG_ERR_INV_SEXP);
s++;
@@ -986,31 +990,45 @@ _ksba_keyinfo_from_sexp (ksba_const_sexp_t sexp,
n = strtoul (s, &endp, 10);
s = endp;
if (!n || *s != ':')
- return gpg_error (GPG_ERR_INV_SEXP); /* we don't allow empty lengths */
+ return gpg_error (GPG_ERR_INV_SEXP); /* We don't allow empty lengths. */
s++;
- oid = oid_from_buffer (s, n, &oidlen, &pkalgo, 0);
- if (!oid)
+
+ algo_oid = oid_from_buffer (s, n, &pkalgo, algoinfomode);
+ if (!algo_oid)
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
s += n;
- /* Collect all the values */
+ /* Collect all the values. */
+ force_pkalgo = 0;
for (parmidx = 0; *s != ')' ; parmidx++)
{
if (parmidx >= DIM(parm))
- return gpg_error (GPG_ERR_GENERAL);
+ {
+ err = gpg_error (GPG_ERR_GENERAL);
+ goto leave;
+ }
if (*s != '(')
- return gpg_error (digitp(s)? GPG_ERR_UNKNOWN_SEXP:GPG_ERR_INV_SEXP);
+ {
+ err = gpg_error (digitp(s)? GPG_ERR_UNKNOWN_SEXP:GPG_ERR_INV_SEXP);
+ goto leave;
+ }
s++;
n = strtoul (s, &endp, 10);
s = endp;
if (!n || *s != ':')
- return gpg_error (GPG_ERR_INV_SEXP);
+ {
+ err = gpg_error (GPG_ERR_INV_SEXP);
+ goto leave;
+ }
s++;
parm[parmidx].name = s;
parm[parmidx].namelen = n;
s += n;
if (!digitp(s))
- return gpg_error (GPG_ERR_UNKNOWN_SEXP); /* ... or invalid S-Exp. */
+ {
+ err = gpg_error (GPG_ERR_UNKNOWN_SEXP); /* ... or invalid S-Exp. */
+ goto leave;
+ }
n = strtoul (s, &endp, 10);
s = endp;
@@ -1021,580 +1039,318 @@ _ksba_keyinfo_from_sexp (ksba_const_sexp_t sexp,
parm[parmidx].valuelen = n;
s += n;
if ( *s != ')')
- return gpg_error (GPG_ERR_UNKNOWN_SEXP); /* ... or invalid S-Exp. */
+ {
+ err = gpg_error (GPG_ERR_UNKNOWN_SEXP); /* ... or invalid S-Exp. */
+ goto leave;
+ }
s++;
+
+ if (parm[parmidx].namelen == 5
+ && !memcmp (parm[parmidx].name, "curve", 5)
+ && !curve_oid)
+ {
+ curve_oid = get_ecc_curve_oid (parm[parmidx].value,
+ parm[parmidx].valuelen, &force_pkalgo);
+ parmidx--; /* No need to store this parameter. */
+ }
}
s++;
+ /* Allow for optional elements. */
+ if (*s == '(')
+ {
+ int depth = 1;
+ err = sskip (&s, &depth);
+ if (err)
+ goto leave;
+ }
/* We need another closing parenthesis. */
if ( *s != ')' )
- return gpg_error (GPG_ERR_INV_SEXP);
-
- /* Describe the parameters in the order we want them and construct
- IDXTBL to access them. For DSA wie also set algoparmdesc so
- that we can later build the parameters for the
- algorithmIdentifier. */
- algoparmdesc = NULL;
- switch (pkalgo)
{
- case PKALGO_RSA: parmdesc = "ne"; break;
- case PKALGO_DSA: parmdesc = "y" ; algoparmdesc = "pqg"; break;
- case PKALGO_ECC: parmdesc = "Cq"; break;
- default: return gpg_error (GPG_ERR_UNKNOWN_ALGORITHM);
+ err = gpg_error (GPG_ERR_INV_SEXP);
+ goto leave;
}
- idxtbllen = 0;
- for (s = parmdesc; *s; s++)
+ if (force_pkalgo)
+ pkalgo = force_pkalgo;
+
+ /* Describe the parameters in the order we want them. For DSA wie
+ * also set algoparmdesc so that we can later build the parameters
+ * for the algorithmIdentifier. */
+ algoparmdesc = NULL;
+ switch (pkalgo)
{
- for (i=0; i < parmidx; i++)
- {
- assert (idxtbllen < DIM (idxtbl));
- switch (*s)
- {
- case 'C': /* Magic value for "curve". */
- if (parm[i].namelen == 5 && !memcmp (parm[i].name, "curve", 5))
- {
- idxtbl[idxtbllen++] = i;
- i = parmidx; /* Break inner loop. */
- }
- break;
- default:
- if (parm[i].namelen == 1 && parm[i].name[0] == *s)
- {
- idxtbl[idxtbllen++] = i;
- i = parmidx; /* Break inner loop. */
- }
- break;
- }
- }
+ case PKALGO_RSA:
+ parmdesc = algoinfomode? "" : "ne";
+ break;
+ case PKALGO_DSA:
+ parmdesc = algoinfomode? "" : "y";
+ algoparmdesc = "pqg";
+ break;
+ case PKALGO_ECC:
+ parmdesc = algoinfomode? "" : "q";
+ break;
+ case PKALGO_ED25519:
+ case PKALGO_X25519:
+ case PKALGO_ED448:
+ case PKALGO_X448:
+ parmdesc = algoinfomode? "" : "q";
+ if (curve_oid)
+ algo_oid = curve_oid;
+ break;
+ default:
+ err = gpg_error (GPG_ERR_UNKNOWN_ALGORITHM);
+ goto leave;
}
- if (idxtbllen != strlen (parmdesc))
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- if (pkalgo == PKALGO_ECC)
+ /* Create a builder. */
+ dbld = _ksba_der_builder_new (0);
+ if (!dbld)
{
- curve_oid = get_ecc_curve_oid (parm[idxtbl[0]].value,
- parm[idxtbl[0]].valuelen,
- &curve_oidlen);
- if (!curve_oid)
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
+ err = gpg_error_from_syserror ();
+ goto leave;
}
+ /* The outer sequence. */
+ if (!algoinfomode)
+ _ksba_der_add_tag (dbld, 0, TYPE_SEQUENCE);
+ /* The sequence. */
+ _ksba_der_add_tag (dbld, 0, TYPE_SEQUENCE);
+ /* The object id. */
+ _ksba_der_add_oid (dbld, algo_oid);
- /* Create write object. */
- err = ksba_writer_new (&writer);
- if (err)
- goto leave;
- err = ksba_writer_set_mem (writer, 1024);
- if (err)
- goto leave;
-
- /* We create the keyinfo in 2 steps:
-
- 1. We build the inner one and encapsulate it in a bit string.
-
- 2. We create the outer sequence include the algorithm identifier
- and the bit string from step 1.
- */
- if (pkalgo == PKALGO_ECC)
+ /* The parameter. */
+ if (algoparmdesc)
{
- /* Write the bit string header and the number of unused bits. */
- err = _ksba_ber_write_tl (writer, TYPE_BIT_STRING, CLASS_UNIVERSAL,
- 0, parm[idxtbl[1]].valuelen + 1);
- if (!err)
- err = ksba_writer_write (writer, "", 1);
- /* And the actual raw value. */
- if (!err)
- err = ksba_writer_write (writer, parm[idxtbl[1]].value,
- parm[idxtbl[1]].valuelen);
- if (err)
- goto leave;
-
+ /* Write the sequence tag followed by the integers. */
+ _ksba_der_add_tag (dbld, 0, TYPE_SEQUENCE);
+ for (s = algoparmdesc; *s; s++)
+ for (i=0; i < parmidx; i++)
+ if (parm[i].namelen == 1 && parm[i].name[0] == *s)
+ {
+ _ksba_der_add_int (dbld, parm[i].value, parm[i].valuelen, 1);
+ break; /* inner loop */
+ }
+ _ksba_der_add_end (dbld);
}
- else /* RSA and DSA */
+ else if (pkalgo == PKALGO_ECC && !algoinfomode)
{
- /* Calculate the size of the sequence value and the size of the
- bit string value. NOt ethat in case there is only one
- integer to write, no sequence is used. */
- for (n=0, i=0; i < idxtbllen; i++ )
- {
- n += _ksba_ber_count_tl (TYPE_INTEGER, CLASS_UNIVERSAL, 0,
- parm[idxtbl[i]].valuelen);
- n += parm[idxtbl[i]].valuelen;
- }
-
- n1 = 1; /* # of unused bits. */
- if (idxtbllen > 1)
- n1 += _ksba_ber_count_tl (TYPE_SEQUENCE, CLASS_UNIVERSAL, 1, n);
- n1 += n;
-
- /* Write the bit string header and the number of unused bits. */
- err = _ksba_ber_write_tl (writer, TYPE_BIT_STRING, CLASS_UNIVERSAL,
- 0, n1);
- if (!err)
- err = ksba_writer_write (writer, "", 1);
- if (err)
- goto leave;
-
- /* Write the sequence tag and the integers. */
- if (idxtbllen > 1)
- err = _ksba_ber_write_tl (writer, TYPE_SEQUENCE, CLASS_UNIVERSAL, 1,n);
- if (err)
- goto leave;
- for (i=0; i < idxtbllen; i++)
+ /* We only support the namedCurve choice for ECC parameters. */
+ if (!curve_oid)
{
- /* fixme: we should make sure that the integer conforms to the
- ASN.1 encoding rules. */
- err = _ksba_ber_write_tl (writer, TYPE_INTEGER, CLASS_UNIVERSAL, 0,
- parm[idxtbl[i]].valuelen);
- if (!err)
- err = ksba_writer_write (writer, parm[idxtbl[i]].value,
- parm[idxtbl[i]].valuelen);
- if (err)
- goto leave;
+ err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
+ goto leave;
}
+ _ksba_der_add_oid (dbld, curve_oid);
}
-
- /* Get the encoded bit string. */
- bitstr_value = ksba_writer_snatch_mem (writer, &bitstr_len);
- if (!bitstr_value)
+ else if (pkalgo == PKALGO_RSA)
{
- err = gpg_error (GPG_ERR_ENOMEM);
- goto leave;
+ _ksba_der_add_ptr (dbld, 0, TYPE_NULL, NULL, 0);
}
- /* If the algorithmIdentifier requires a sequence with parameters,
- build them now. We can reuse the IDXTBL for that. */
- if (algoparmdesc)
+ _ksba_der_add_end (dbld); /* sequence. */
+
+ /* Add the bit string if we are not in algoinfomode. */
+ if (!algoinfomode)
{
- idxtbllen = 0;
- for (s = algoparmdesc; *s; s++)
+ if (*parmdesc == 'q' && !parmdesc[1])
{
+ /* This is ECC - Q is directly written as a bit string. */
for (i=0; i < parmidx; i++)
+ if (parm[i].namelen == 1 && parm[i].name[0] == 'q')
+ {
+ if ((parm[i].valuelen & 1) && parm[i].valuelen > 32
+ && (parm[i].value[0] == 0x40
+ || parm[i].value[0] == 0x41
+ || parm[i].value[0] == 0x42))
+ {
+ /* Odd length and prefixed with 0x40 - this is the
+ * rfc4880bis indicator octet for extended point
+ * formats - we may not emit that octet here. */
+ _ksba_der_add_bts (dbld, parm[i].value+1,
+ parm[i].valuelen-1, 0);
+ }
+ else
+ _ksba_der_add_bts (dbld, parm[i].value, parm[i].valuelen, 0);
+ break;
+ }
+ }
+ else /* Non-ECC - embed the values. */
+ {
+ dbld2 = _ksba_der_builder_new (10);
+ if (!dbld2)
{
- assert (idxtbllen < DIM (idxtbl));
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+
+ /* Note that no sequence is used if only one integer is written. */
+ if (parmdesc[0] && parmdesc[1])
+ _ksba_der_add_tag (dbld2, 0, TYPE_SEQUENCE);
+
+ for (s = parmdesc; *s; s++)
+ for (i=0; i < parmidx; i++)
if (parm[i].namelen == 1 && parm[i].name[0] == *s)
{
- idxtbl[idxtbllen++] = i;
- break;
+ _ksba_der_add_int (dbld2, parm[i].value, parm[i].valuelen, 1);
+ break; /* inner loop */
}
- }
- }
- if (idxtbllen != strlen (algoparmdesc))
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
-
- err = ksba_writer_set_mem (writer, 1024);
- if (err)
- goto leave;
- /* Calculate the size of the sequence. */
- for (n=0, i=0; i < idxtbllen; i++ )
- {
- n += _ksba_ber_count_tl (TYPE_INTEGER, CLASS_UNIVERSAL, 0,
- parm[idxtbl[i]].valuelen);
- n += parm[idxtbl[i]].valuelen;
- }
- /* n += _ksba_ber_count_tl (TYPE_SEQUENCE, CLASS_UNIVERSAL, 1, n); */
+ if (parmdesc[0] && parmdesc[1])
+ _ksba_der_add_end (dbld2);
- /* Write the sequence tag followed by the integers. */
- err = _ksba_ber_write_tl (writer, TYPE_SEQUENCE, CLASS_UNIVERSAL, 1, n);
- if (err)
- goto leave;
- for (i=0; i < idxtbllen; i++)
- {
- err = _ksba_ber_write_tl (writer, TYPE_INTEGER, CLASS_UNIVERSAL, 0,
- parm[idxtbl[i]].valuelen);
- if (!err)
- err = ksba_writer_write (writer, parm[idxtbl[i]].value,
- parm[idxtbl[i]].valuelen);
+ err = _ksba_der_builder_get (dbld2, &tmpder, &tmpderlen);
if (err)
goto leave;
+ _ksba_der_add_bts (dbld, tmpder, tmpderlen, 0);
+ xfree (tmpder);
}
- /* Get the encoded sequence. */
- algoparmseq_value = ksba_writer_snatch_mem (writer, &algoparmseq_len);
- if (!algoparmseq_value)
- {
- err = gpg_error (GPG_ERR_ENOMEM);
- goto leave;
- }
- }
- else
- algoparmseq_len = 0;
-
- /* Reinitialize the buffer to create the outer sequence. */
- err = ksba_writer_set_mem (writer, 1024);
- if (err)
- goto leave;
-
- /* Calulate lengths. */
- n = _ksba_ber_count_tl (TYPE_OBJECT_ID, CLASS_UNIVERSAL, 0, oidlen);
- n += oidlen;
- if (algoparmseq_len)
- {
- n += algoparmseq_len;
- }
- else if (pkalgo == PKALGO_ECC)
- {
- n += _ksba_ber_count_tl (TYPE_OBJECT_ID, CLASS_UNIVERSAL,
- 0, curve_oidlen);
- n += curve_oidlen;
- }
- else if (pkalgo == PKALGO_RSA)
- {
- n += _ksba_ber_count_tl (TYPE_NULL, CLASS_UNIVERSAL, 0, 0);
- }
-
- n1 = n;
- n1 += _ksba_ber_count_tl (TYPE_SEQUENCE, CLASS_UNIVERSAL, 1, n);
- n1 += bitstr_len;
-
- /* The outer sequence. */
- err = _ksba_ber_write_tl (writer, TYPE_SEQUENCE, CLASS_UNIVERSAL, 1, n1);
- if (err)
- goto leave;
-
- /* The sequence. */
- err = _ksba_ber_write_tl (writer, TYPE_SEQUENCE, CLASS_UNIVERSAL, 1, n);
- if (err)
- goto leave;
-
- /* The object id. */
- err = _ksba_ber_write_tl (writer, TYPE_OBJECT_ID,CLASS_UNIVERSAL, 0, oidlen);
- if (!err)
- err = ksba_writer_write (writer, oid, oidlen);
- if (err)
- goto leave;
-
- /* The parameter. */
- if (algoparmseq_len)
- {
- err = ksba_writer_write (writer, algoparmseq_value, algoparmseq_len);
- }
- else if (pkalgo == PKALGO_ECC)
- {
- err = _ksba_ber_write_tl (writer, TYPE_OBJECT_ID, CLASS_UNIVERSAL,
- 0, curve_oidlen);
- if (!err)
- err = ksba_writer_write (writer, curve_oid, curve_oidlen);
- }
- else if (pkalgo == PKALGO_RSA)
- {
- err = _ksba_ber_write_tl (writer, TYPE_NULL, CLASS_UNIVERSAL, 0, 0);
+ _ksba_der_add_end (dbld); /* Outer sequence. */
}
- if (err)
- goto leave;
-
- /* Append the pre-constructed bit string. */
- err = ksba_writer_write (writer, bitstr_value, bitstr_len);
- if (err)
- goto leave;
/* Get the result. */
- *r_der = ksba_writer_snatch_mem (writer, r_derlen);
- if (!*r_der)
- err = gpg_error (GPG_ERR_ENOMEM);
+ err = _ksba_der_builder_get (dbld, r_der, r_derlen);
leave:
- ksba_writer_release (writer);
- xfree (bitstr_value);
+ _ksba_der_release (dbld2);
+ _ksba_der_release (dbld);
xfree (curve_oid);
return err;
}
-/* Take a sig-val s-expression and convert it into a DER encoded
- algorithmInfo. Unfortunately this function clones a lot of code
- from _ksba_keyinfo_from_sexp. */
+/* Helper function to parse the parameters used for rsaPSS.
+ * Given this sample DER object in (DER,DERLEN):
+ *
+ * SEQUENCE {
+ * [0] {
+ * SEQUENCE {
+ * OBJECT IDENTIFIER sha-512 (2 16 840 1 101 3 4 2 3)
+ * }
+ * }
+ * [1] {
+ * SEQUENCE {
+ * OBJECT IDENTIFIER pkcs1-MGF (1 2 840 113549 1 1 8)
+ * SEQUENCE {
+ * OBJECT IDENTIFIER sha-512 (2 16 840 1 101 3 4 2 3)
+ * }
+ * }
+ * }
+ * [2] {
+ * INTEGER 64
+ * }
+ * }
+ *
+ * The function returns the first OID at R_PSSHASH and the salt length
+ * at R_SALTLEN. If the salt length is missing its default value is
+ * returned. In case object does not resemble a the expected rsaPSS
+ * parameters GPG_ERR_INV_OBJ is returned; other errors are returned
+ * for an syntatically invalid object. On error NULL is stored at
+ * R_PSSHASH.
+ */
gpg_error_t
-_ksba_algoinfo_from_sexp (ksba_const_sexp_t sexp,
- unsigned char **r_der, size_t *r_derlen)
+_ksba_keyinfo_get_pss_info (const unsigned char *der, size_t derlen,
+ char **r_psshash, unsigned int *r_saltlen)
{
gpg_error_t err;
- const unsigned char *s;
- char *endp;
- unsigned long n;
- const unsigned char *oid;
- int oidlen;
- unsigned char *curve_oid = NULL;
- size_t curve_oidlen;
- pkalgo_t pkalgo;
- int i;
- struct {
- const char *name;
- int namelen;
- const unsigned char *value;
- int valuelen;
- } parm[10];
- int parmidx;
- int idxtbl[10];
- int idxtbllen;
- const char *parmdesc, *algoparmdesc;
- ksba_writer_t writer = NULL;
- void *algoparmseq_value = NULL;
- size_t algoparmseq_len;
-
- if (!sexp)
- return gpg_error (GPG_ERR_INV_VALUE);
-
- s = sexp;
- if (*s != '(')
- return gpg_error (GPG_ERR_INV_SEXP);
- s++;
-
- n = strtoul (s, &endp, 10);
- s = endp;
- if (!n || *s != ':')
- return gpg_error (GPG_ERR_INV_SEXP); /* We don't allow empty lengths. */
- s++;
- if (n == 7 && !memcmp (s, "sig-val", 7))
- s += 7;
- else if (n == 10 && !memcmp (s, "public-key", 10))
- s += 10;
- else
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
-
- if (*s != '(')
- return gpg_error (digitp (s)? GPG_ERR_UNKNOWN_SEXP : GPG_ERR_INV_SEXP);
- s++;
-
- /* Break out the algorithm ID */
- n = strtoul (s, &endp, 10);
- s = endp;
- if (!n || *s != ':')
- return gpg_error (GPG_ERR_INV_SEXP); /* We don't allow empty lengths. */
- s++;
- oid = oid_from_buffer (s, n, &oidlen, &pkalgo, 1);
- if (!oid)
- return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
- s += n;
-
- /* Collect all the values */
- for (parmidx = 0; *s != ')' ; parmidx++)
- {
- if (parmidx >= DIM(parm))
- return gpg_error (GPG_ERR_GENERAL);
- if (*s != '(')
- return gpg_error (digitp(s)? GPG_ERR_UNKNOWN_SEXP:GPG_ERR_INV_SEXP);
- s++;
- n = strtoul (s, &endp, 10);
- s = endp;
- if (!n || *s != ':')
- return gpg_error (GPG_ERR_INV_SEXP);
- s++;
- parm[parmidx].name = s;
- parm[parmidx].namelen = n;
- s += n;
- if (!digitp(s))
- return gpg_error (GPG_ERR_UNKNOWN_SEXP); /* ... or invalid S-Exp. */
-
- n = strtoul (s, &endp, 10);
- s = endp;
- if (!n || *s != ':')
- return gpg_error (GPG_ERR_INV_SEXP);
- s++;
- parm[parmidx].value = s;
- parm[parmidx].valuelen = n;
- s += n;
- if ( *s != ')')
- return gpg_error (GPG_ERR_UNKNOWN_SEXP); /* ... or invalid S-Exp. */
- s++;
- }
- s++;
- /* We need another closing parenthesis. */
- if ( *s != ')' )
- return gpg_error (GPG_ERR_INV_SEXP);
+ struct tag_info ti;
+ char *psshash = NULL;
+ char *tmpoid = NULL;
+ unsigned int saltlen;
- /* Describe the parameters in the order we want them and construct
- IDXTBL to access them. For DSA wie also set algoparmdesc so
- that we can later build the parameters for the
- algorithmIdentifier. */
- algoparmdesc = NULL;
- switch (pkalgo)
- {
- case PKALGO_RSA: parmdesc = ""; break;
- case PKALGO_DSA: parmdesc = "" ; algoparmdesc = "pqg"; break;
- case PKALGO_ECC: parmdesc = "C"; break;
- default: return gpg_error (GPG_ERR_UNKNOWN_ALGORITHM);
- }
-
- idxtbllen = 0;
- for (s = parmdesc; *s; s++)
- {
- for (i=0; i < parmidx; i++)
- {
- assert (idxtbllen < DIM (idxtbl));
- switch (*s)
- {
- case 'C': /* Magic value for "curve". */
- if (parm[i].namelen == 5 && !memcmp (parm[i].name, "curve", 5))
- {
- idxtbl[idxtbllen++] = i;
- i = parmidx; /* Break inner loop. */
- }
- break;
- default:
- if (parm[i].namelen == 1 && parm[i].name[0] == *s)
- {
- idxtbl[idxtbllen++] = i;
- i = parmidx; /* Break inner loop. */
- }
- break;
- }
- }
- }
- if (idxtbllen != strlen (parmdesc))
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
+ *r_psshash = NULL;
+ *r_saltlen = 0;
- if (pkalgo == PKALGO_ECC)
- {
- curve_oid = get_ecc_curve_oid (parm[idxtbl[0]].value,
- parm[idxtbl[0]].valuelen,
- &curve_oidlen);
- if (!curve_oid)
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- }
+ err = parse_sequence (&der, &derlen, &ti);
+ if (err)
+ goto leave;
+ /* Get the hash algo. */
+ err = parse_context_tag (&der, &derlen, &ti, 0);
+ if (err)
+ goto unknown_parms;
+ err = parse_sequence (&der, &derlen, &ti);
+ if (err)
+ goto unknown_parms;
+ err = parse_object_id_into_str (&der, &derlen, &psshash);
+ if (err)
+ goto unknown_parms;
+ err = parse_optional_null (&der, &derlen, NULL);
+ if (err)
+ goto unknown_parms;
- /* Create write object. */
- err = ksba_writer_new (&writer);
+ /* Check the MGF OID and that its hash algo matches. */
+ err = parse_context_tag (&der, &derlen, &ti, 1);
+ if (err)
+ goto unknown_parms;
+ err = parse_sequence (&der, &derlen, &ti);
if (err)
goto leave;
- err = ksba_writer_set_mem (writer, 1024);
+ err = parse_object_id_into_str (&der, &derlen, &tmpoid);
+ if (err)
+ goto unknown_parms;
+ if (strcmp (tmpoid, "1.2.840.113549.1.1.8")) /* MGF1 */
+ goto unknown_parms;
+ err = parse_sequence (&der, &derlen, &ti);
if (err)
goto leave;
-
- /* Create the sequence of the algorithm identifier. */
-
- /* If the algorithmIdentifier requires a sequence with parameters,
- build them now. We can reuse the IDXTBL for that. */
- if (algoparmdesc)
+ xfree (tmpoid);
+ err = parse_object_id_into_str (&der, &derlen, &tmpoid);
+ if (err)
+ goto unknown_parms;
+ if (strcmp (tmpoid, psshash))
+ goto unknown_parms;
+ err = parse_optional_null (&der, &derlen, NULL);
+ if (err)
+ goto unknown_parms;
+
+ /* Get the optional saltLength. */
+ err = parse_context_tag (&der, &derlen, &ti, 2);
+ if (gpg_err_code (err) == GPG_ERR_INV_OBJ
+ || gpg_err_code (err) == GPG_ERR_FALSE)
+ saltlen = 20; /* Optional element - use default value */
+ else if (err)
+ goto unknown_parms;
+ else
{
- idxtbllen = 0;
- for (s = algoparmdesc; *s; s++)
- {
- for (i=0; i < parmidx; i++)
- {
- assert (idxtbllen < DIM (idxtbl));
- if (parm[i].namelen == 1 && parm[i].name[0] == *s)
- {
- idxtbl[idxtbllen++] = i;
- break;
- }
- }
- }
- if (idxtbllen != strlen (algoparmdesc))
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
-
- err = ksba_writer_set_mem (writer, 1024);
+ err = parse_integer (&der, &derlen, &ti);
if (err)
goto leave;
-
- /* Calculate the size of the sequence. */
- for (n=0, i=0; i < idxtbllen; i++ )
- {
- n += _ksba_ber_count_tl (TYPE_INTEGER, CLASS_UNIVERSAL, 0,
- parm[idxtbl[i]].valuelen);
- n += parm[idxtbl[i]].valuelen;
- }
-
- /* Write the sequence tag followed by the integers. */
- err = _ksba_ber_write_tl (writer, TYPE_SEQUENCE, CLASS_UNIVERSAL, 1, n);
- if (err)
- goto leave;
- for (i=0; i < idxtbllen; i++)
- {
- err = _ksba_ber_write_tl (writer, TYPE_INTEGER, CLASS_UNIVERSAL, 0,
- parm[idxtbl[i]].valuelen);
- if (!err)
- err = ksba_writer_write (writer, parm[idxtbl[i]].value,
- parm[idxtbl[i]].valuelen);
- if (err)
- goto leave;
- }
-
- /* Get the encoded sequence. */
- algoparmseq_value = ksba_writer_snatch_mem (writer, &algoparmseq_len);
- if (!algoparmseq_value)
+ for (saltlen=0; ti.length; ti.length--)
{
- err = gpg_error (GPG_ERR_ENOMEM);
- goto leave;
+ saltlen <<= 8;
+ saltlen |= (*der++) & 0xff;
+ derlen--;
}
}
- else
- algoparmseq_len = 0;
-
- /* Reinitialize the buffer to create the sequence. */
- err = ksba_writer_set_mem (writer, 1024);
- if (err)
- goto leave;
-
- /* Calulate lengths. */
- n = _ksba_ber_count_tl (TYPE_OBJECT_ID, CLASS_UNIVERSAL, 0, oidlen);
- n += oidlen;
- if (algoparmseq_len)
- {
- n += algoparmseq_len;
- }
- else if (pkalgo == PKALGO_ECC)
- {
- n += _ksba_ber_count_tl (TYPE_OBJECT_ID, CLASS_UNIVERSAL,
- 0, curve_oidlen);
- n += curve_oidlen;
- }
- else if (pkalgo == PKALGO_RSA)
- {
- n += _ksba_ber_count_tl (TYPE_NULL, CLASS_UNIVERSAL, 0, 0);
- }
-
- /* Write the sequence. */
- err = _ksba_ber_write_tl (writer, TYPE_SEQUENCE, CLASS_UNIVERSAL, 1, n);
- if (err)
- goto leave;
-
- /* Write the object id. */
- err = _ksba_ber_write_tl (writer, TYPE_OBJECT_ID, CLASS_UNIVERSAL, 0, oidlen);
- if (!err)
- err = ksba_writer_write (writer, oid, oidlen);
- if (err)
- goto leave;
- /* Write the parameters. */
- if (algoparmseq_len)
- {
- err = ksba_writer_write (writer, algoparmseq_value, algoparmseq_len);
- }
- else if (pkalgo == PKALGO_ECC)
- {
- /* We only support the namedCuve choice for ECC parameters. */
- err = _ksba_ber_write_tl (writer, TYPE_OBJECT_ID, CLASS_UNIVERSAL,
- 0, curve_oidlen);
- if (!err)
- err = ksba_writer_write (writer, curve_oid, curve_oidlen);
- }
- else if (pkalgo == PKALGO_RSA)
- {
- err = _ksba_ber_write_tl (writer, TYPE_NULL, CLASS_UNIVERSAL, 0, 0);
- }
- if (err)
- goto leave;
+ /* All fine. */
+ *r_psshash = psshash;
+ psshash = NULL;
+ *r_saltlen = saltlen;
+ err = 0;
+ goto leave;
- /* Get the result. */
- *r_der = ksba_writer_snatch_mem (writer, r_derlen);
- if (!*r_der)
- err = gpg_error (GPG_ERR_ENOMEM);
+ unknown_parms:
+ err = gpg_error (GPG_ERR_INV_OBJ);
leave:
- ksba_writer_release (writer);
- xfree (curve_oid);
+ xfree (psshash);
+ xfree (tmpoid);
return err;
}
-
/* Mode 0: work as described under _ksba_sigval_to_sexp
- mode 1: work as described under _ksba_encval_to_sexp */
+ * mode 1: work as described under _ksba_encval_to_sexp
+ * mode 2: same as mode 1 but for ECDH; in this mode
+ * KEYENCRYALO, KEYWRAPALGO, ENCRKEY, ENCRYKLEYLEN
+ * are also required.
+ */
static gpg_error_t
cryptval_to_sexp (int mode, const unsigned char *der, size_t derlen,
+ const char *keyencralgo, const char *keywrapalgo,
+ const void *encrkey, size_t encrkeylen,
ksba_sexp_t *r_string)
{
gpg_error_t err;
@@ -1606,6 +1362,10 @@ cryptval_to_sexp (int mode, const unsigned char *der, size_t derlen,
const unsigned char *ctrl;
const char *elem;
struct stringbuf sb;
+ size_t parm_off, parm_len;
+ int parm_type;
+ char *pss_hash = NULL;
+ unsigned int salt_length = 0;
/* FIXME: The entire function is very similar to keyinfo_to_sexp */
*r_string = NULL;
@@ -1615,9 +1375,8 @@ cryptval_to_sexp (int mode, const unsigned char *der, size_t derlen,
else
algo_table = enc_algo_table;
-
err = get_algorithm (1, der, derlen, &nread, &off, &len, &is_bitstr,
- NULL, NULL, NULL);
+ &parm_off, &parm_len, &parm_type);
if (err)
return err;
@@ -1628,11 +1387,27 @@ cryptval_to_sexp (int mode, const unsigned char *der, size_t derlen,
&& !memcmp (der+off, algo_table[algoidx].oid, len))
break;
}
+
if (!algo_table[algoidx].oid)
return gpg_error (GPG_ERR_UNKNOWN_ALGORITHM);
if (!algo_table[algoidx].supported)
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
+ if (parm_type == TYPE_SEQUENCE
+ && algo_table[algoidx].supported == SUPPORTED_RSAPSS)
+ {
+ /* This is rsaPSS and we collect the parameters. We simplify
+ * this by assuming that pkcs1-MGF is used with an identical
+ * hash algorithm. All other kinds of parameters are ignored. */
+ err = _ksba_keyinfo_get_pss_info (der + parm_off, parm_len,
+ &pss_hash, &salt_length);
+ if (gpg_err_code (err) == GPG_ERR_INV_OBJ)
+ err = 0;
+ if (err)
+ return err;
+ }
+
+
der += nread;
derlen -= nread;
@@ -1655,40 +1430,62 @@ cryptval_to_sexp (int mode, const unsigned char *der, size_t derlen,
/* FIXME: We don't release the stringbuf in case of error
better let the macro jump to a label */
- elem = algo_table[algoidx].elem_string;
- ctrl = algo_table[algoidx].ctrl_string;
- for (; *elem; ctrl++, elem++)
+ if (!mode && (algo_table[algoidx].pkalgo == PKALGO_ED25519
+ ||algo_table[algoidx].pkalgo == PKALGO_ED448))
{
- int is_int;
-
- if ( (*ctrl & 0x80) && !elem[1] )
- { /* Hack to allow a raw value */
- is_int = 1;
- len = derlen;
- }
- else
+ /* EdDSA is special: R and S are simply concatenated; see rfc8410. */
+ put_stringbuf (&sb, "(1:r");
+ put_stringbuf_mem_sexp (&sb, der, derlen/2);
+ put_stringbuf (&sb, ")");
+ der += derlen/2;
+ derlen /= 2;
+ put_stringbuf (&sb, "(1:s");
+ put_stringbuf_mem_sexp (&sb, der, derlen);
+ put_stringbuf (&sb, ")");
+ }
+ else
+ {
+ elem = algo_table[algoidx].elem_string;
+ ctrl = algo_table[algoidx].ctrl_string;
+ for (; *elem; ctrl++, elem++)
{
- if (!derlen)
- return gpg_error (GPG_ERR_INV_KEYINFO);
- c = *der++; derlen--;
- if ( c != *ctrl )
- return gpg_error (GPG_ERR_UNEXPECTED_TAG);
- is_int = c == 0x02;
- TLV_LENGTH (der);
- }
- if (is_int && *elem != '-')
- { /* take this integer */
- char tmp[2];
+ int is_int;
- put_stringbuf (&sb, "(");
- tmp[0] = *elem; tmp[1] = 0;
- put_stringbuf_sexp (&sb, tmp);
- put_stringbuf_mem_sexp (&sb, der, len);
- der += len;
- derlen -= len;
- put_stringbuf (&sb, ")");
+ if ( (*ctrl & 0x80) && !elem[1] )
+ { /* Hack to allow a raw value */
+ is_int = 1;
+ len = derlen;
+ }
+ else
+ {
+ if (!derlen)
+ return gpg_error (GPG_ERR_INV_KEYINFO);
+ c = *der++; derlen--;
+ if ( c != *ctrl )
+ return gpg_error (GPG_ERR_UNEXPECTED_TAG);
+ is_int = c == 0x02;
+ TLV_LENGTH (der);
+ }
+ if (is_int && *elem != '-')
+ { /* take this integer */
+ char tmp[2];
+
+ put_stringbuf (&sb, "(");
+ tmp[0] = *elem; tmp[1] = 0;
+ put_stringbuf_sexp (&sb, tmp);
+ put_stringbuf_mem_sexp (&sb, der, len);
+ der += len;
+ derlen -= len;
+ put_stringbuf (&sb, ")");
+ }
}
}
+ if (mode == 2) /* ECDH */
+ {
+ put_stringbuf (&sb, "(1:s");
+ put_stringbuf_mem_sexp (&sb, encrkey, encrkeylen);
+ put_stringbuf (&sb, ")");
+ }
put_stringbuf (&sb, ")");
if (!mode && algo_table[algoidx].digest_string)
{
@@ -1697,12 +1494,31 @@ cryptval_to_sexp (int mode, const unsigned char *der, size_t derlen,
put_stringbuf_sexp (&sb, algo_table[algoidx].digest_string);
put_stringbuf (&sb, ")");
}
+ if (!mode && pss_hash)
+ {
+ put_stringbuf (&sb, "(5:flags3:pss)");
+ put_stringbuf (&sb, "(9:hash-algo");
+ put_stringbuf_sexp (&sb, pss_hash);
+ put_stringbuf (&sb, ")");
+ put_stringbuf (&sb, "(11:salt-length");
+ put_stringbuf_uint (&sb, salt_length);
+ put_stringbuf (&sb, ")");
+ }
+ if (mode == 2) /* ECDH */
+ {
+ put_stringbuf (&sb, "(9:encr-algo");
+ put_stringbuf_sexp (&sb, keyencralgo);
+ put_stringbuf (&sb, ")(9:wrap-algo");
+ put_stringbuf_sexp (&sb, keywrapalgo);
+ put_stringbuf (&sb, ")");
+ }
put_stringbuf (&sb, ")");
*r_string = get_stringbuf (&sb);
if (!*r_string)
return gpg_error (GPG_ERR_ENOMEM);
+ xfree (pss_hash);
return 0;
}
@@ -1732,35 +1548,86 @@ gpg_error_t
_ksba_sigval_to_sexp (const unsigned char *der, size_t derlen,
ksba_sexp_t *r_string)
{
- return cryptval_to_sexp (0, der, derlen, r_string);
+ return cryptval_to_sexp (0, der, derlen, NULL, NULL, NULL, 0, r_string);
}
/* Assume that der is a buffer of length DERLEN with a DER encoded
- Asn.1 structure like this:
-
- SEQUENCE {
- algorithm OBJECT IDENTIFIER,
- parameters ANY DEFINED BY algorithm OPTIONAL }
- encryptedKey OCTET STRING
-
- We only allow parameters == NULL.
-
- The function parses this structure and creates a S-Exp suitable to be
- used as encrypted value in Libgcrypt's public key functions:
-
- (enc-val
- (<algo>
- (<param_name1> <mpi>)
- ...
- (<param_namen> <mpi>)
- ))
-
- The S-Exp will be returned in a string which the caller must free.
- We don't pass an ASN.1 node here but a plain memory block. */
+ * ASN.1 structure like this:
+ *
+ * SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL
+ * }
+ * encryptedKey OCTET STRING
+ *
+ * The function parses this structure and creates a S-expression
+ * suitable to be used as encrypted value in Libgcrypt's public key
+ * functions:
+ *
+ * (enc-val
+ * (<algo>
+ * (<param_name1> <mpi>)
+ * ...
+ * (<param_namen> <mpi>)
+ * ))
+ *
+ * The S-expression will be returned in a string which the caller must
+ * free. Note that the input buffer may not a proper ASN.1 object but
+ * a plain memory block; this is becuase the SEQUENCE is followed by
+ * an OCTET STRING or BIT STRING.
+ */
gpg_error_t
_ksba_encval_to_sexp (const unsigned char *der, size_t derlen,
ksba_sexp_t *r_string)
{
- return cryptval_to_sexp (1, der, derlen, r_string);
+ return cryptval_to_sexp (1, der, derlen, NULL, NULL, NULL, 0, r_string);
+}
+
+
+/* Assume that der is a buffer of length DERLEN with a DER encoded
+ * ASN.1 structure like this:
+ *
+ * [1] {
+ * SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL
+ * }
+ * encryptedKey BIT STRING
+ * }
+ *
+ * The function parses this structure and creates an S-expression
+ * conveying all parameters required for ECDH:
+ *
+ * (enc-val
+ * (ecdh
+ * (e <octetstring>)
+ * (s <octetstring>)
+ * (ukm <octetstring>)
+ * (encr-algo <oid>)
+ * (wrap-algo <oid>)))
+ *
+ * E is the ephemeral public key and S is the encrypted key. The user
+ * keying material (ukm) is optional. The S-expression will be
+ * returned in a string which the caller must free.
+ */
+gpg_error_t
+_ksba_encval_kari_to_sexp (const unsigned char *der, size_t derlen,
+ const char *keyencralgo, const char *keywrapalgo,
+ const void *enckey, size_t enckeylen,
+ ksba_sexp_t *r_string)
+{
+ gpg_error_t err;
+ struct tag_info ti;
+ size_t save_derlen = derlen;
+
+ err = parse_context_tag (&der, &derlen, &ti, 1);
+ if (err)
+ return err;
+ if (save_derlen < ti.nhdr)
+ return gpg_error (GPG_ERR_INV_BER);
+ derlen = save_derlen - ti.nhdr;
+ return cryptval_to_sexp (2, der, derlen,
+ keyencralgo, keywrapalgo, enckey, enckeylen,
+ r_string);
}