scd:nks: Add support for signing plain SHA-3 digests.

* scd/app-nks.c (do_sign): Handle plain SHA-3 digests and verify
encoding of ASN.1 encoded hashes.
--

This makes it possible to create CSRs for NetKey card keys which are
signed with SHA256 by default.

GnuPG-bug-id: 5184
This commit is contained in:
Ingo Klöcker 2021-01-06 12:09:19 +01:00
parent f4a8be0950
commit 8fe976d5b9
1 changed files with 66 additions and 16 deletions

View File

@ -1665,6 +1665,22 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
static unsigned char rmd160_prefix[15] = /* Object ID is 1.3.36.3.2.1 */
{ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03,
0x02, 0x01, 0x05, 0x00, 0x04, 0x14 };
static unsigned char sha224_prefix[19] = /* (2.16.840.1.101.3.4.2.4) */
{ 0x30, 0x2D, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48,
0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04,
0x1C };
static unsigned char sha256_prefix[19] = /* (2.16.840.1.101.3.4.2.1) */
{ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
0x00, 0x04, 0x20 };
static unsigned char sha384_prefix[19] = /* (2.16.840.1.101.3.4.2.2) */
{ 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
0x00, 0x04, 0x30 };
static unsigned char sha512_prefix[19] = /* (2.16.840.1.101.3.4.2.3) */
{ 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
0x00, 0x04, 0x40 };
gpg_error_t err;
int idx;
int pwid;
@ -1677,8 +1693,20 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
switch (indatalen)
{
case 16: case 20: case 35: case 47: case 51: case 67: case 83: break;
default: return gpg_error (GPG_ERR_INV_VALUE);
case 20: // plain SHA-1 or RMD160 digest
case 28: // plain SHA-224 digest
case 32: // plain SHA-256 digest
case 48: // plain SHA-384 digest
case 64: // plain SHA-512 digest
case 35: // ASN.1 encoded SHA-1 or RMD160 digest
case 47: // ASN.1 encoded SHA-224 digest
case 51: // ASN.1 encoded SHA-256 digest
case 67: // ASN.1 encoded SHA-384 digest
case 83: // ASN.1 encoded SHA-512 digest
break;
default:
log_debug ("invalid length of input data: %zu\n", indatalen);
return gpg_error (GPG_ERR_INV_VALUE);
}
err = find_fid_by_keyref (app, keyidstr, &idx, NULL);
@ -1693,7 +1721,10 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
}
if (!filelist[idx].issignkey)
return gpg_error (GPG_ERR_INV_ID);
{
log_debug ("key %s is not a signing key\n", keyidstr);
return gpg_error (GPG_ERR_INV_ID);
}
kid = filelist[idx].kid;
@ -1704,8 +1735,23 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|| indatalen == 67
|| indatalen == 83))
{
/* The caller send data matching the length of the ASN.1 encoded
hash for SHA-{1,224,256,384,512}. Assume that is okay. */
/* Verify that the caller has sent a proper ASN.1 encoded hash
for RMD160 or SHA-{1,224,256,384,512}. */
#define X(algo,prefix,plaindigestlen) \
if (hashalgo == (algo) \
&& indatalen == sizeof prefix + (plaindigestlen) \
&& !memcmp (indata, prefix, sizeof prefix)) \
;
X(GCRY_MD_RMD160, rmd160_prefix, 20)
else X(GCRY_MD_SHA1, sha1_prefix, 20)
else X(GCRY_MD_SHA224, sha224_prefix, 28)
else X(GCRY_MD_SHA256, sha256_prefix, 32)
else X(GCRY_MD_SHA384, sha384_prefix, 48)
else X(GCRY_MD_SHA512, sha512_prefix, 64)
else
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
#undef X
log_assert (indatalen <= sizeof data);
memcpy (data, indata, indatalen);
datalen = indatalen;
@ -1723,20 +1769,24 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
memcpy (data, indata, indatalen);
datalen = 35;
}
else if (indatalen == 20)
{
if (hashalgo == GCRY_MD_SHA1)
memcpy (data, sha1_prefix, 15);
else if (hashalgo == GCRY_MD_RMD160)
memcpy (data, rmd160_prefix, 15);
else
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
memcpy (data+15, indata, indatalen);
datalen = 35;
/* Concatenate prefix and digest. */
#define X(algo,prefix,plaindigestlen) \
if ((hashalgo == (algo)) && (indatalen == (plaindigestlen))) \
{ \
datalen = sizeof prefix + indatalen; \
log_assert (datalen <= sizeof data); \
memcpy (data, prefix, sizeof prefix); \
memcpy (data + sizeof prefix, indata, indatalen); \
}
else X(GCRY_MD_RMD160, rmd160_prefix, 20)
else X(GCRY_MD_SHA1, sha1_prefix, 20)
else X(GCRY_MD_SHA224, sha224_prefix, 28)
else X(GCRY_MD_SHA256, sha256_prefix, 32)
else X(GCRY_MD_SHA384, sha384_prefix, 48)
else X(GCRY_MD_SHA512, sha512_prefix, 64)
else
return gpg_error (GPG_ERR_INV_VALUE);
#undef X
/* Send an MSE for PSO:Computer_Signature. */
if (app->appversion > 2)