scd: Add support of ECC pubkey attribute.

* scd/app-openpgp.c (ECC_FLAG_PUBKEY): New.
(send_key_attr, get_public_key, ecc_writekey, do_auth, do_decipher)
(parse_algorithm_attribute): Check ECC_FLAG_DJB_TWEAK.
(build_ecc_privkey_template): Add ECC_Q and ECC_Q_LEN.
Support offering public key when ECC_FLAG_PUBKEY sets.
(ecc_writekey): Supply ECC_Q and ECC_Q_LEN.
(parse_algorithm_attribute): Parse pubkey-required byte.

--

OpenPGPcard protocol specification version 3.2 supports algorithm
attributes for ECC key which specifies public key data is required for
"keytocard" command.  This change supports the feature.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
NIIBE Yutaka 2016-09-16 15:20:32 +09:00
parent c0e620cee8
commit dd06d33655
1 changed files with 45 additions and 16 deletions

View File

@ -236,6 +236,7 @@ struct app_local_s {
}; };
#define ECC_FLAG_DJB_TWEAK (1 << 0) #define ECC_FLAG_DJB_TWEAK (1 << 0)
#define ECC_FLAG_PUBKEY (1 << 1)
/***** Local prototypes *****/ /***** Local prototypes *****/
@ -910,7 +911,7 @@ send_key_attr (ctrl_t ctrl, app_t app, const char *keyword, int keyno)
snprintf (buffer, sizeof buffer, "%d %d %s", snprintf (buffer, sizeof buffer, "%d %d %s",
keyno+1, keyno+1,
keyno==1? PUBKEY_ALGO_ECDH : keyno==1? PUBKEY_ALGO_ECDH :
app->app_local->keyattr[keyno].ecc.flags? (app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK)?
PUBKEY_ALGO_EDDSA : PUBKEY_ALGO_ECDSA, PUBKEY_ALGO_EDDSA : PUBKEY_ALGO_ECDSA,
openpgp_oid_to_curve (app->app_local->keyattr[keyno].ecc.oid, 0)); openpgp_oid_to_curve (app->app_local->keyattr[keyno].ecc.oid, 0));
} }
@ -1387,7 +1388,7 @@ get_public_key (app_t app, int keyno)
if ((app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA if ((app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA
|| (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC || (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC
&& !app->app_local->keyattr[keyno].ecc.flags)) && !(app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK)))
&& mlen && (*m & 0x80)) && mlen && (*m & 0x80))
{ /* Prepend numbers with a 0 if needed for MPI. */ { /* Prepend numbers with a 0 if needed for MPI. */
*mbuf = 0; *mbuf = 0;
@ -1395,7 +1396,7 @@ get_public_key (app_t app, int keyno)
mlen++; mlen++;
} }
else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC
&& app->app_local->keyattr[keyno].ecc.flags) && (app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK))
{ /* Prepend 0x40 prefix. */ { /* Prepend 0x40 prefix. */
*mbuf = 0x40; *mbuf = 0x40;
memcpy (mbuf+1, m, mlen); memcpy (mbuf+1, m, mlen);
@ -1429,7 +1430,7 @@ get_public_key (app_t app, int keyno)
{ {
char *format; char *format;
if (!app->app_local->keyattr[keyno].ecc.flags) if (!(app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK))
format = "(public-key(ecc(curve%s)(q%b)))"; format = "(public-key(ecc(curve%s)(q%b)))";
else if (keyno == 1) else if (keyno == 1)
format = "(public-key(ecc(curve%s)(flags djb-tweak)(q%b)))"; format = "(public-key(ecc(curve%s)(flags djb-tweak)(q%b)))";
@ -2633,9 +2634,10 @@ build_privkey_template (app_t app, int keyno,
static gpg_error_t static gpg_error_t
build_ecc_privkey_template (app_t app, int keyno, build_ecc_privkey_template (app_t app, int keyno,
const unsigned char *ecc_d, size_t ecc_d_len, const unsigned char *ecc_d, size_t ecc_d_len,
const unsigned char *ecc_q, size_t ecc_q_len,
unsigned char **result, size_t *resultlen) unsigned char **result, size_t *resultlen)
{ {
unsigned char privkey[2]; unsigned char privkey[2+2];
size_t privkey_len; size_t privkey_len;
unsigned char exthdr[2+2+1]; unsigned char exthdr[2+2+1];
size_t exthdr_len; size_t exthdr_len;
@ -2645,8 +2647,10 @@ build_ecc_privkey_template (app_t app, int keyno,
size_t datalen; size_t datalen;
unsigned char *template; unsigned char *template;
size_t template_size; size_t template_size;
int pubkey_required;
(void)app; pubkey_required = !!(app->app_local->keyattr[keyno].ecc.flags
& ECC_FLAG_PUBKEY);
*result = NULL; *result = NULL;
*resultlen = 0; *resultlen = 0;
@ -2658,8 +2662,15 @@ build_ecc_privkey_template (app_t app, int keyno,
tp += add_tlv (tp, 0x92, ecc_d_len); tp += add_tlv (tp, 0x92, ecc_d_len);
datalen += ecc_d_len; datalen += ecc_d_len;
if (pubkey_required)
{
tp += add_tlv (tp, 0x99, ecc_q_len);
datalen += ecc_q_len;
}
privkey_len = tp - privkey; privkey_len = tp - privkey;
/* Build the extended header list without the private key template. */ /* Build the extended header list without the private key template. */
tp = exthdr; tp = exthdr;
*tp++ = keyno ==0 ? 0xb6 : keyno == 1? 0xb8 : 0xa4; *tp++ = keyno ==0 ? 0xb6 : keyno == 1? 0xb8 : 0xa4;
@ -2693,6 +2704,12 @@ build_ecc_privkey_template (app_t app, int keyno,
memcpy (tp, ecc_d, ecc_d_len); memcpy (tp, ecc_d, ecc_d_len);
tp += ecc_d_len; tp += ecc_d_len;
if (pubkey_required)
{
memcpy (tp, ecc_q, ecc_q_len);
tp += ecc_q_len;
}
assert (tp - template == template_size); assert (tp - template == template_size);
*result = template; *result = template;
@ -3348,7 +3365,8 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
if (app->app_local->keyattr[keyno].key_type != KEY_TYPE_ECC if (app->app_local->keyattr[keyno].key_type != KEY_TYPE_ECC
|| app->app_local->keyattr[keyno].ecc.oid != oidstr || app->app_local->keyattr[keyno].ecc.oid != oidstr
|| app->app_local->keyattr[keyno].ecc.flags != flag_djb_tweak) || (flag_djb_tweak !=
(app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK)))
{ {
if (app->app_local->extcap.algo_attr_change) if (app->app_local->extcap.algo_attr_change)
{ {
@ -3387,6 +3405,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
err = build_ecc_privkey_template (app, keyno, err = build_ecc_privkey_template (app, keyno,
ecc_d, ecc_d_len, ecc_d, ecc_d_len,
ecc_q, ecc_q_len,
&template, &template_len); &template, &template_len);
if (err) if (err)
goto leave; goto leave;
@ -3991,7 +4010,7 @@ do_auth (app_t app, const char *keyidstr,
if (app->app_local->keyattr[2].key_type == KEY_TYPE_ECC) if (app->app_local->keyattr[2].key_type == KEY_TYPE_ECC)
{ {
if (!app->app_local->keyattr[2].ecc.flags if (!(app->app_local->keyattr[2].ecc.flags & ECC_FLAG_DJB_TWEAK)
&& (indatalen == 51 || indatalen == 67 || indatalen == 83)) && (indatalen == 51 || indatalen == 67 || indatalen == 83))
{ {
const char *p = (const char *)indata + 19; const char *p = (const char *)indata + 19;
@ -4190,7 +4209,7 @@ do_decipher (app_t app, const char *keyidstr,
{ {
int old_format_len = 0; int old_format_len = 0;
if (app->app_local->keyattr[1].ecc.flags) if ((app->app_local->keyattr[1].ecc.flags & ECC_FLAG_DJB_TWEAK))
{ {
if (indatalen > 32 && (indatalen % 2)) if (indatalen > 32 && (indatalen % 2))
{ /* { /*
@ -4258,7 +4277,7 @@ do_decipher (app_t app, const char *keyidstr,
outdata, outdatalen); outdata, outdatalen);
xfree (fixbuf); xfree (fixbuf);
if (app->app_local->keyattr[1].key_type == KEY_TYPE_ECC if (app->app_local->keyattr[1].key_type == KEY_TYPE_ECC
&& app->app_local->keyattr[1].ecc.flags) && (app->app_local->keyattr[1].ecc.flags & ECC_FLAG_DJB_TWEAK))
{ /* Add the prefix 0x40 */ { /* Add the prefix 0x40 */
fixbuf = xtrymalloc (*outdatalen + 1); fixbuf = xtrymalloc (*outdatalen + 1);
if (!fixbuf) if (!fixbuf)
@ -4550,7 +4569,19 @@ parse_algorithm_attribute (app_t app, int keyno)
else if (*buffer == PUBKEY_ALGO_ECDH || *buffer == PUBKEY_ALGO_ECDSA else if (*buffer == PUBKEY_ALGO_ECDH || *buffer == PUBKEY_ALGO_ECDSA
|| *buffer == PUBKEY_ALGO_EDDSA) || *buffer == PUBKEY_ALGO_EDDSA)
{ {
const char *oid = ecc_oid (buffer + 1, buflen - 1); const char *oid;
int oidlen = buflen - 1;
app->app_local->keyattr[keyno].ecc.flags = 0;
if (buffer[buflen-1] == 0x00 || buffer[buflen-1] == 0xff)
{ /* Found "pubkey required"-byte for private key template. */
oidlen--;
if (buffer[buflen-1] == 0xff)
app->app_local->keyattr[keyno].ecc.flags |= ECC_FLAG_PUBKEY;
}
oid = ecc_oid (buffer + 1, oidlen);
if (!oid) if (!oid)
log_printhex ("Curve with OID not supported: ", buffer+1, buflen-1); log_printhex ("Curve with OID not supported: ", buffer+1, buflen-1);
@ -4562,14 +4593,12 @@ parse_algorithm_attribute (app_t app, int keyno)
|| (*buffer == PUBKEY_ALGO_ECDH || (*buffer == PUBKEY_ALGO_ECDH
&& !strcmp (app->app_local->keyattr[keyno].ecc.oid, && !strcmp (app->app_local->keyattr[keyno].ecc.oid,
"1.3.6.1.4.1.3029.1.5.1"))) "1.3.6.1.4.1.3029.1.5.1")))
app->app_local->keyattr[keyno].ecc.flags = ECC_FLAG_DJB_TWEAK; app->app_local->keyattr[keyno].ecc.flags |= ECC_FLAG_DJB_TWEAK;
else
app->app_local->keyattr[keyno].ecc.flags = 0;
if (opt.verbose) if (opt.verbose)
log_printf log_printf
("ECC, curve=%s%s\n", app->app_local->keyattr[keyno].ecc.oid, ("ECC, curve=%s%s\n", app->app_local->keyattr[keyno].ecc.oid,
!app->app_local->keyattr[keyno].ecc.flags ? "": !(app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK)?
keyno==1? " (djb-tweak)": " (eddsa)"); "": keyno==1? " (djb-tweak)": " (eddsa)");
} }
} }
else if (opt.verbose) else if (opt.verbose)