summaryrefslogtreecommitdiffstats
path: root/sm
diff options
context:
space:
mode:
authorDamien Goutte-Gattat via Gnupg-devel <gnupg-devel@gnupg.org>2018-11-16 02:27:37 +0100
committerNIIBE Yutaka <gniibe@fsij.org>2019-02-15 03:01:20 +0100
commit74e9b579ca273fc07be090bb5fb7800a97b1b452 (patch)
treeac80d4c0c09325a15eda7bd757782ef85ff6cbd0 /sm
parentpo: Correct a simple typo in the Norwegian translation (diff)
downloadgnupg2-74e9b579ca273fc07be090bb5fb7800a97b1b452.tar.xz
gnupg2-74e9b579ca273fc07be090bb5fb7800a97b1b452.zip
sm: Support generation of card-based ECDSA CSR.
* sm/call-agent.c (gpgsm_scd_pksign): Identify type of signing key and format resulting S-expression accordingly. * sm/misc.c (transform_sigval): Support ECDSA signatures. -- Current GpgSM implementation assumes card-based keys are RSA keys. This patch introduces support for ECDSA keys. By itself this patch is not sufficient, we also need support from libksba. GnuPG-bug-id: 4092 Signed-off-by: Damien Goutte-Gattat <dgouttegattat@incenp.org>
Diffstat (limited to 'sm')
-rw-r--r--sm/call-agent.c57
-rw-r--r--sm/misc.c75
2 files changed, 98 insertions, 34 deletions
diff --git a/sm/call-agent.c b/sm/call-agent.c
index 20d879fa4..6ac715fab 100644
--- a/sm/call-agent.c
+++ b/sm/call-agent.c
@@ -334,7 +334,7 @@ gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc,
unsigned char *digest, size_t digestlen, int digestalgo,
unsigned char **r_buf, size_t *r_buflen )
{
- int rc, i;
+ int rc, i, pkalgo;
char *p, line[ASSUAN_LINELENGTH];
membuf_t data;
size_t len;
@@ -342,6 +342,7 @@ gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc,
unsigned char *sigbuf;
size_t sigbuflen;
struct default_inq_parm_s inq_parm;
+ gcry_sexp_t sig;
(void)desc;
@@ -366,6 +367,23 @@ gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc,
if (digestlen*2 + 50 > DIM(line))
return gpg_error (GPG_ERR_GENERAL);
+ /* Get the key type from the scdaemon. */
+ snprintf (line, DIM(line), "SCD READKEY %s", keyid);
+ init_membuf (&data, 1024);
+ rc = assuan_transact (agent_ctx, line,
+ put_membuf_cb, &data, NULL, NULL, NULL, NULL);
+ if (rc)
+ {
+ xfree (get_membuf (&data, &len));
+ return rc;
+ }
+
+ p = get_membuf (&data, &len);
+ pkalgo = get_pk_algo_from_canon_sexp (p, len);
+ xfree (p);
+ if (!pkalgo)
+ return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
+
p = stpcpy (line, "SCD SETDATA " );
for (i=0; i < digestlen ; i++, p += 2 )
sprintf (p, "%02X", digest[i]);
@@ -386,24 +404,31 @@ gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc,
}
sigbuf = get_membuf (&data, &sigbuflen);
- /* Create an S-expression from it which is formatted like this:
- "(7:sig-val(3:rsa(1:sSIGBUFLEN:SIGBUF)))" Fixme: If a card ever
- creates non-RSA keys we need to change things. */
- *r_buflen = 21 + 11 + sigbuflen + 4;
- p = xtrymalloc (*r_buflen);
- *r_buf = (unsigned char*)p;
- if (!p)
+ switch(pkalgo)
{
- xfree (sigbuf);
- return 0;
+ case GCRY_PK_RSA:
+ rc = gcry_sexp_build (&sig, NULL, "(sig-val(rsa(s%b)))",
+ sigbuflen, sigbuf);
+ break;
+
+ case GCRY_PK_ECC:
+ rc = gcry_sexp_build (&sig, NULL, "(sig-val(ecdsa(r%b)(s%b)))",
+ sigbuflen/2, sigbuf,
+ sigbuflen/2, sigbuf + sigbuflen/2);
+ break;
+
+ default:
+ rc = gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
+ break;
}
- p = stpcpy (p, "(7:sig-val(3:rsa(1:s" );
- sprintf (p, "%u:", (unsigned int)sigbuflen);
- p += strlen (p);
- memcpy (p, sigbuf, sigbuflen);
- p += sigbuflen;
- strcpy (p, ")))");
xfree (sigbuf);
+ if (rc)
+ return rc;
+
+ rc = make_canon_sexp (sig, r_buf, r_buflen);
+ gcry_sexp_release (sig);
+ if (rc)
+ return rc;
assert (gcry_sexp_canon_len (*r_buf, *r_buflen, NULL, NULL));
return 0;
diff --git a/sm/misc.c b/sm/misc.c
index 6d047763b..9bf528513 100644
--- a/sm/misc.c
+++ b/sm/misc.c
@@ -109,13 +109,16 @@ transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo,
gpg_error_t err;
const unsigned char *buf, *tok;
size_t buflen, toklen;
- int depth, last_depth1, last_depth2;
+ int depth, last_depth1, last_depth2, pkalgo;
int is_pubkey = 0;
- const unsigned char *rsa_s = NULL;
- size_t rsa_s_len = 0;
+ const unsigned char *rsa_s, *ecc_r, *ecc_s;
+ size_t rsa_s_len, ecc_r_len, ecc_s_len;
const char *oid;
gcry_sexp_t sexp;
+ rsa_s = ecc_r = ecc_s = NULL;
+ rsa_s_len = ecc_r_len = ecc_s_len = 0;
+
*r_newsigval = NULL;
if (r_newsigvallen)
*r_newsigvallen = 0;
@@ -137,7 +140,13 @@ transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo,
return err;
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
return err;
- if (!tok || toklen != 3 || memcmp ("rsa", tok, toklen))
+ if (!tok)
+ return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
+ if (toklen == 3 && !memcmp ("rsa", tok, 3))
+ pkalgo = GCRY_PK_RSA;
+ else if (toklen == 5 && !memcmp ("ecdsa", tok, 5))
+ pkalgo = GCRY_PK_ECC;
+ else
return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
last_depth1 = depth;
@@ -150,16 +159,27 @@ transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo,
return err;
if (tok && toklen == 1)
{
- const unsigned char **mpi;
- size_t *mpi_len;
+ const unsigned char **mpi = NULL;
+ size_t *mpi_len = NULL;
switch (*tok)
{
- case 's': mpi = &rsa_s; mpi_len = &rsa_s_len; break;
+ case 's':
+ if (pkalgo == GCRY_PK_RSA)
+ {
+ mpi = &rsa_s;
+ mpi_len = &rsa_s_len;
+ }
+ else if (pkalgo == GCRY_PK_ECC)
+ {
+ mpi = &ecc_s;
+ mpi_len = &ecc_s_len;
+ }
+ break;
+
+ case 'r': mpi = &ecc_r; mpi_len = &ecc_r_len; break;
default: mpi = NULL; mpi_len = NULL; break;
}
- if (mpi && *mpi)
- return gpg_error (GPG_ERR_DUP_VALUE);
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
return err;
@@ -182,33 +202,52 @@ transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo,
return err;
/* Map the hash algorithm to an OID. */
- switch (mdalgo)
+ switch (mdalgo | (pkalgo << 8))
{
- case GCRY_MD_SHA1:
+ case GCRY_MD_SHA1 | (GCRY_PK_RSA << 8):
oid = "1.2.840.113549.1.1.5"; /* sha1WithRSAEncryption */
break;
- case GCRY_MD_SHA256:
+ case GCRY_MD_SHA256 | (GCRY_PK_RSA << 8):
oid = "1.2.840.113549.1.1.11"; /* sha256WithRSAEncryption */
break;
- case GCRY_MD_SHA384:
+ case GCRY_MD_SHA384 | (GCRY_PK_RSA << 8):
oid = "1.2.840.113549.1.1.12"; /* sha384WithRSAEncryption */
break;
- case GCRY_MD_SHA512:
+ case GCRY_MD_SHA512 | (GCRY_PK_RSA << 8):
oid = "1.2.840.113549.1.1.13"; /* sha512WithRSAEncryption */
break;
+ case GCRY_MD_SHA224 | (GCRY_PK_ECC << 8):
+ oid = "1.2.840.10045.4.3.1"; /* ecdsa-with-sha224 */
+ break;
+
+ case GCRY_MD_SHA256 | (GCRY_PK_ECC << 8):
+ oid = "1.2.840.10045.4.3.2"; /* ecdsa-with-sha256 */
+ break;
+
+ case GCRY_MD_SHA384 | (GCRY_PK_ECC << 8):
+ oid = "1.2.840.10045.4.3.3"; /* ecdsa-with-sha384 */
+ break;
+
+ case GCRY_MD_SHA512 | (GCRY_PK_ECC << 8):
+ oid = "1.2.840.10045.4.3.4"; /* ecdsa-with-sha512 */
+ break;
+
default:
return gpg_error (GPG_ERR_DIGEST_ALGO);
}
- if (rsa_s && !is_pubkey)
- err = gcry_sexp_build (&sexp, NULL, "(sig-val(%s(s%b)))",
- oid, (int)rsa_s_len, rsa_s);
- else
+ if (is_pubkey)
err = gcry_sexp_build (&sexp, NULL, "(sig-val(%s))", oid);
+ else if (pkalgo == GCRY_PK_RSA)
+ err = gcry_sexp_build (&sexp, NULL, "(sig-val(%s(s%b)))", oid,
+ (int)rsa_s_len, rsa_s);
+ else if (pkalgo == GCRY_PK_ECC)
+ err = gcry_sexp_build (&sexp, NULL, "(sig-val(%s(r%b)(s%b)))", oid,
+ (int)ecc_r_len, ecc_r, (int)ecc_s_len, ecc_s);
if (err)
return err;
err = make_canon_sexp (sexp, r_newsigval, r_newsigvallen);