mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
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:
parent
c0e620cee8
commit
dd06d33655
@ -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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user