mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
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>
This commit is contained in:
parent
b89f1790e0
commit
74e9b579ca
@ -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 *digest, size_t digestlen, int digestalgo,
|
||||||
unsigned char **r_buf, size_t *r_buflen )
|
unsigned char **r_buf, size_t *r_buflen )
|
||||||
{
|
{
|
||||||
int rc, i;
|
int rc, i, pkalgo;
|
||||||
char *p, line[ASSUAN_LINELENGTH];
|
char *p, line[ASSUAN_LINELENGTH];
|
||||||
membuf_t data;
|
membuf_t data;
|
||||||
size_t len;
|
size_t len;
|
||||||
@ -342,6 +342,7 @@ gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc,
|
|||||||
unsigned char *sigbuf;
|
unsigned char *sigbuf;
|
||||||
size_t sigbuflen;
|
size_t sigbuflen;
|
||||||
struct default_inq_parm_s inq_parm;
|
struct default_inq_parm_s inq_parm;
|
||||||
|
gcry_sexp_t sig;
|
||||||
|
|
||||||
(void)desc;
|
(void)desc;
|
||||||
|
|
||||||
@ -366,6 +367,23 @@ gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc,
|
|||||||
if (digestlen*2 + 50 > DIM(line))
|
if (digestlen*2 + 50 > DIM(line))
|
||||||
return gpg_error (GPG_ERR_GENERAL);
|
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 " );
|
p = stpcpy (line, "SCD SETDATA " );
|
||||||
for (i=0; i < digestlen ; i++, p += 2 )
|
for (i=0; i < digestlen ; i++, p += 2 )
|
||||||
sprintf (p, "%02X", digest[i]);
|
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);
|
sigbuf = get_membuf (&data, &sigbuflen);
|
||||||
|
|
||||||
/* Create an S-expression from it which is formatted like this:
|
switch(pkalgo)
|
||||||
"(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)
|
|
||||||
{
|
{
|
||||||
xfree (sigbuf);
|
case GCRY_PK_RSA:
|
||||||
return 0;
|
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);
|
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));
|
assert (gcry_sexp_canon_len (*r_buf, *r_buflen, NULL, NULL));
|
||||||
return 0;
|
return 0;
|
||||||
|
75
sm/misc.c
75
sm/misc.c
@ -109,13 +109,16 @@ transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo,
|
|||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
const unsigned char *buf, *tok;
|
const unsigned char *buf, *tok;
|
||||||
size_t buflen, toklen;
|
size_t buflen, toklen;
|
||||||
int depth, last_depth1, last_depth2;
|
int depth, last_depth1, last_depth2, pkalgo;
|
||||||
int is_pubkey = 0;
|
int is_pubkey = 0;
|
||||||
const unsigned char *rsa_s = NULL;
|
const unsigned char *rsa_s, *ecc_r, *ecc_s;
|
||||||
size_t rsa_s_len = 0;
|
size_t rsa_s_len, ecc_r_len, ecc_s_len;
|
||||||
const char *oid;
|
const char *oid;
|
||||||
gcry_sexp_t sexp;
|
gcry_sexp_t sexp;
|
||||||
|
|
||||||
|
rsa_s = ecc_r = ecc_s = NULL;
|
||||||
|
rsa_s_len = ecc_r_len = ecc_s_len = 0;
|
||||||
|
|
||||||
*r_newsigval = NULL;
|
*r_newsigval = NULL;
|
||||||
if (r_newsigvallen)
|
if (r_newsigvallen)
|
||||||
*r_newsigvallen = 0;
|
*r_newsigvallen = 0;
|
||||||
@ -137,7 +140,13 @@ transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo,
|
|||||||
return err;
|
return err;
|
||||||
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
||||||
return err;
|
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);
|
return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
|
||||||
|
|
||||||
last_depth1 = depth;
|
last_depth1 = depth;
|
||||||
@ -150,16 +159,27 @@ transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo,
|
|||||||
return err;
|
return err;
|
||||||
if (tok && toklen == 1)
|
if (tok && toklen == 1)
|
||||||
{
|
{
|
||||||
const unsigned char **mpi;
|
const unsigned char **mpi = NULL;
|
||||||
size_t *mpi_len;
|
size_t *mpi_len = NULL;
|
||||||
|
|
||||||
switch (*tok)
|
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;
|
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)))
|
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
||||||
return err;
|
return err;
|
||||||
@ -182,33 +202,52 @@ transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo,
|
|||||||
return err;
|
return err;
|
||||||
|
|
||||||
/* Map the hash algorithm to an OID. */
|
/* 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 */
|
oid = "1.2.840.113549.1.1.5"; /* sha1WithRSAEncryption */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GCRY_MD_SHA256:
|
case GCRY_MD_SHA256 | (GCRY_PK_RSA << 8):
|
||||||
oid = "1.2.840.113549.1.1.11"; /* sha256WithRSAEncryption */
|
oid = "1.2.840.113549.1.1.11"; /* sha256WithRSAEncryption */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GCRY_MD_SHA384:
|
case GCRY_MD_SHA384 | (GCRY_PK_RSA << 8):
|
||||||
oid = "1.2.840.113549.1.1.12"; /* sha384WithRSAEncryption */
|
oid = "1.2.840.113549.1.1.12"; /* sha384WithRSAEncryption */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GCRY_MD_SHA512:
|
case GCRY_MD_SHA512 | (GCRY_PK_RSA << 8):
|
||||||
oid = "1.2.840.113549.1.1.13"; /* sha512WithRSAEncryption */
|
oid = "1.2.840.113549.1.1.13"; /* sha512WithRSAEncryption */
|
||||||
break;
|
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:
|
default:
|
||||||
return gpg_error (GPG_ERR_DIGEST_ALGO);
|
return gpg_error (GPG_ERR_DIGEST_ALGO);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rsa_s && !is_pubkey)
|
if (is_pubkey)
|
||||||
err = gcry_sexp_build (&sexp, NULL, "(sig-val(%s(s%b)))",
|
|
||||||
oid, (int)rsa_s_len, rsa_s);
|
|
||||||
else
|
|
||||||
err = gcry_sexp_build (&sexp, NULL, "(sig-val(%s))", oid);
|
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)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
err = make_canon_sexp (sexp, r_newsigval, r_newsigvallen);
|
err = make_canon_sexp (sexp, r_newsigval, r_newsigvallen);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user