[PATCH] scd: support any curves defined by libgcrypt.

Bertrand Jacquin bertrand at jacquin.bzh
Mon Aug 17 02:10:45 CEST 2015


Hi,

This patch introduce as issue with OpenGPG Card FTS-01. I've run a git 
bisect to be able to point that particular commit.

I have a FTS-01 OpenGPG card with a EdDSA sign key and a EdDSA auth key 
and using gpg-agent as a ssh agent. Since that particular commit, info 
given by gpg-agent to ssh-add are not conform for ssh:

$ ssh-add -l
error fetching identities for protocol 2: invalid format
The agent has no identities.

scdaemon is returning the following to gpg-agent:

[pid 14395] read(4, "GETATTR SERIALNO\n", 1002) = 17
[pid 14395] write(5, "S SERIALNO D276000124010200FFFE50FF6A060000", 43) 
= 43
[pid 14395] write(5, "\n", 1)           = 1
[pid 14395] write(5, "OK", 2)           = 2
[pid 14395] write(5, "\n", 1)           = 1
[pid 14395] read(4, "READKEY OPENPGP.3\n", 1002) = 18
[pid 14395] write(5, "D 
(10:public-key(3:ecc(5:curve7:Ed25519)(5:flags5:eddsa)(1:q33:@\7\323|\256d\353Mo\16^Onu\212\330\333\256Z8Uo\366x\33\337}\333s\220\310\241N)))\n", 
100) = 100
[pid 14395] write(5, "OK", 2)           = 2
[pid 14395] write(5, "\n", 1)           = 1
[pid 14395] read(4, "GETATTR $DISPSERIALNO\n", 1002) = 22
[pid 14395] write(5, "S $DISPSERIALNO FFFE50FF6A06", 28) = 28

gpg-agent is returning the following to ssh-add:

[pid 14471] write(5, "\0\0\0T", 4)      = 4
[pid 14471] write(5, 
"\f\0\0\0\1\0\0\0004\0\0\0\vssh-ed25519\0\0\0!@\7\323|\256d\353Mo\16^Onu\212\330\333\256Z8Uo\366x\33\337}\333s\220\310\241N\0\0\0\23cardno:FFFE50FF6A06", 
84) = 84
[pid 14471] read(5, "", 1)              = 0
[pid 14471] write(9, "RESTART", 7)      = 7

Here is the details about my setup:

$ /usr/bin/usb_strings.py
Device:
     Vendor: Free Software Initiative of Japan
    Product: Gnuk Token
     Serial: FSIJ-1.1.7-87062311
   Revision: release/1.1.7
     Config: FST_01:dfu=no:debug=no:pinpad=no:certdo=yes
        Sys: 2.1
      Board: FST-01

$ gpg --version
gpg (GnuPG) 2.1.7
libgcrypt 1.6.3

$ gpg --card-status | grep -E 'Version|Key\ attributes|key'
Version ..........: 2.0
Key attributes ...: ed25519 rsa2048 ed25519
Signature key ....: DB2A 5D8D 1506 34ED 349C  32E4 71D8 37C4 7EA9 B667
Encryption key....: 1FBC 26CC 2BAB CE26 A3F8  8D4F C356 C8D7 FF60 3A1A
Authentication key: 3266 F1CD 03C5 46F6 22A1  3EBE E710 BC72 3D40 CCE8
General key info..: sub  ed25519/0x71D837C47EA9B667 2014-11-10 Bertrand 
Jacquin <bertrand at jacquin.bzh>

Is there a need to use a particular libgcrypt version ?

Cheers,
Bertrand

On 25/07/2015 04:09, NIIBE Yutaka wrote:
> * g10/call-agent.h (struct agent_card_info_s): Add curve field.
> * g10/call-agent.c (learn_status_cb): Use curve name.
> * g10/card-util.c (card_status): Show pubkey name.
> * scd/app-openpgp.c (struct app_local_s): Record OID and flags.
> (store_fpr): Use ALGO instead of key type.
> (send_key_attr): Use curve name instead of OID.
> (get_public_key): Clean up by OID to curve name.
> (ecc_writekey): Support any curves in libgcrypt.
> (do_genkey, do_auth, ): Follow the change.
> (ecc_oid): New.
> (parse_algorithm_attribute): Show OID here.
> ---
>  g10/call-agent.c  |  28 ++++-
>  g10/call-agent.h  |   5 +-
>  g10/card-util.c   |  19 +--
>  scd/app-openpgp.c | 360 
> +++++++++++++++++++++---------------------------------
>  4 files changed, 180 insertions(+), 232 deletions(-)
> 
> diff --git a/g10/call-agent.c b/g10/call-agent.c
> index edee66e..0df572a 100644
> --- a/g10/call-agent.c
> +++ b/g10/call-agent.c
> @@ -645,14 +645,32 @@ learn_status_cb (void *opaque, const char *line)
>      }
>    else if (keywordlen == 8 && !memcmp (keyword, "KEY-ATTR", 
> keywordlen))
>      {
> -      int keyno, algo, nbits;
> +      int keyno = 0;
> +      int algo = PUBKEY_ALGO_RSA;
> +      int n = 0;
> 
> -      sscanf (line, "%d %d %d", &keyno, &algo, &nbits);
> +      sscanf (line, "%d %d %n", &keyno, &algo, &n);
>        keyno--;
> -      if (keyno >= 0 && keyno < DIM (parm->key_attr))
> +      if (keyno < 0 || keyno >= DIM (parm->key_attr))
> +        return 0;
> +
> +      parm->key_attr[keyno].algo = algo;
> +      if (algo == PUBKEY_ALGO_RSA)
> +        parm->key_attr[keyno].nbits = strtoul (line+n+3, NULL, 10);
> +      else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA
> +               || algo == PUBKEY_ALGO_EDDSA)
>          {
> -          parm->key_attr[keyno].algo = algo;
> -          parm->key_attr[keyno].nbits = nbits;
> +          const char *curve;
> +
> +          i = 0;
> +          do
> +            {
> +              curve = openpgp_enum_curves (&i);
> +              if (!strcmp (curve, line+n))
> +                break;
> +            }
> +          while (curve != NULL);
> +          parm->key_attr[keyno].curve = curve;
>          }
>      }
>    else if (keywordlen == 12 && !memcmp (keyword, "PRIVATE-DO-", 11)
> diff --git a/g10/call-agent.h b/g10/call-agent.h
> index df570a4..70421db 100644
> --- a/g10/call-agent.h
> +++ b/g10/call-agent.h
> @@ -55,7 +55,10 @@ struct agent_card_info_s
>    int chvretry[3];   /* Allowed retries for the CHV; 0 = blocked. */
>    struct {           /* Array with key attributes.  */
>      int algo;              /* Algorithm identifier.  */
> -    unsigned int nbits;    /* Supported keysize.  */
> +    union {
> +      unsigned int nbits;  /* Supported keysize.  */
> +      const char *curve;   /* Name of curve.  */
> +    };
>    } key_attr[3];
>    struct {
>      unsigned int ki:1;     /* Key import available.  */
> diff --git a/g10/card-util.c b/g10/card-util.c
> index 890bf2d..ed69058 100644
> --- a/g10/card-util.c
> +++ b/g10/card-util.c
> @@ -471,9 +471,14 @@ card_status (estream_t fp, char *serialno, size_t
> serialnobuflen)
> 
>        es_fprintf (fp, "forcepin:%d:::\n", !info.chv1_cached);
>        for (i=0; i < DIM (info.key_attr); i++)
> -        if (info.key_attr[0].algo)
> +        if (info.key_attr[0].algo == PUBKEY_ALGO_RSA)
>            es_fprintf (fp, "keyattr:%d:%d:%u:\n", i+1,
>                        info.key_attr[i].algo, info.key_attr[i].nbits);
> +        else if (info.key_attr[i].algo == PUBKEY_ALGO_ECDH
> +                 || info.key_attr[i].algo == PUBKEY_ALGO_ECDSA
> +                 || info.key_attr[i].algo == PUBKEY_ALGO_EDDSA)
> +          es_fprintf (fp, "keyattr:%d:%d:%s:\n", i+1,
> +                      info.key_attr[i].algo, info.key_attr[i].curve);
>        es_fprintf (fp, "maxpinlen:%d:%d:%d:\n",
>                    info.chvmaxlen[0], info.chvmaxlen[1], 
> info.chvmaxlen[2]);
>        es_fprintf (fp, "pinretry:%d:%d:%d:\n",
> @@ -553,12 +558,12 @@ card_status (estream_t fp, char *serialno,
> size_t serialnobuflen)
>          {
>            tty_fprintf (fp,    "Key attributes ...:");
>            for (i=0; i < DIM (info.key_attr); i++)
> -            tty_fprintf (fp, " %u%c",
> -                         info.key_attr[i].nbits,
> -                         info.key_attr[i].algo == 1? 'R':
> -                         info.key_attr[i].algo == 17? 'D':
> -                         info.key_attr[i].algo == 18? 'e':
> -                         info.key_attr[i].algo == 19? 'E': '?');
> +            if (info.key_attr[i].algo == PUBKEY_ALGO_RSA)
> +              tty_fprintf (fp, " rsa%u", info.key_attr[i].nbits);
> +            else if (info.key_attr[i].algo == PUBKEY_ALGO_ECDH
> +                     || info.key_attr[i].algo == PUBKEY_ALGO_ECDSA
> +                     || info.key_attr[i].algo == PUBKEY_ALGO_EDDSA)
> +              tty_fprintf (fp, " %s", info.key_attr[i].curve);
>            tty_fprintf (fp, "\n");
>          }
>        tty_fprintf (fp,    "Max. PIN lengths .: %d %d %d\n",
> diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
> index 81b4923..72f7640 100644
> --- a/scd/app-openpgp.c
> +++ b/scd/app-openpgp.c
> @@ -126,7 +126,6 @@ static struct {
>  typedef enum
>    {
>      KEY_TYPE_ECC,
> -    KEY_TYPE_EDDSA,
>      KEY_TYPE_RSA,
>    }
>  key_type_t;
> @@ -144,18 +143,6 @@ typedef enum
>  rsa_key_format_t;
> 
> 
> -/* Elliptic Curves.  */
> -enum
> -  {
> -    CURVE_NIST_P256,
> -    CURVE_NIST_P384,
> -    CURVE_NIST_P521,
> -    CURVE_SEC_P256K1,
> -    CURVE_ED25519,
> -    CURVE_UNKNOWN,
> -  };
> -
> -
>  /* One cache item for DOs.  */
>  struct cache_s {
>    struct cache_s *next;
> @@ -241,15 +228,14 @@ struct app_local_s {
>          rsa_key_format_t format;
>        } rsa;
>        struct {
> -        int curve;
> +        const char *oid;
> +        int flags;
>        } ecc;
> -      struct {
> -        int curve;
> -      } eddsa;
>      };
>     } keyattr[3];
>  };
> 
> +#define ECC_FLAG_EDDSA (1 << 0)
> 
> 
>  /***** Local prototypes  *****/
> @@ -745,25 +731,12 @@ parse_login_data (app_t app)
>  }
> 
> 
> -static unsigned char
> -get_algo_byte (int keynumber, key_type_t key_type)
> -{
> -  if (key_type == KEY_TYPE_ECC && keynumber != 1)
> -    return PUBKEY_ALGO_ECDSA;
> -  else if (key_type == KEY_TYPE_ECC && keynumber == 1)
> -    return PUBKEY_ALGO_ECDH;
> -  else if (key_type == KEY_TYPE_EDDSA)
> -    return PUBKEY_ALGO_EDDSA;
> -  else
> -    return PUBKEY_ALGO_RSA;
> -}
> -
>  #define MAX_ARGS_STORE_FPR 3
> 
>  /* Note, that FPR must be at least 20 bytes. */
>  static gpg_error_t
>  store_fpr (app_t app, int keynumber, u32 timestamp, unsigned char 
> *fpr,
> -           key_type_t key_type, ...)
> +           int algo, ...)
>  {
>    unsigned int n, nbits;
>    unsigned char *buffer, *p;
> @@ -776,21 +749,17 @@ store_fpr (app_t app, int keynumber, u32
> timestamp, unsigned char *fpr,
>    int i;
> 
>    n = 6;    /* key packet version, 4-byte timestamps, and algorithm */
> -  if (keynumber == 1 && key_type == KEY_TYPE_ECC)
> +  if (algo == PUBKEY_ALGO_ECDH)
>      argc = 3;
>    else
>      argc = 2;
> 
> -  va_start (ap, key_type);
> +  va_start (ap, algo);
>    for (i = 0; i < argc; i++)
>      {
>        m[i] = va_arg (ap, const unsigned char *);
>        mlen[i] = va_arg (ap, size_t);
> -      if (key_type != KEY_TYPE_EDDSA)
> -        /* strip off leading zeroes */
> -        for (; mlen[i] && !*m[i]; mlen[i]--, m[i]++)
> -          ;
> -      if (key_type == KEY_TYPE_RSA || i == 1)
> +      if (algo == PUBKEY_ALGO_RSA || i == 1)
>          n += 2;
>        n += mlen[i];
>      }
> @@ -808,11 +777,11 @@ store_fpr (app_t app, int keynumber, u32
> timestamp, unsigned char *fpr,
>    *p++ = timestamp >> 16;
>    *p++ = timestamp >>  8;
>    *p++ = timestamp;
> -  *p++ = get_algo_byte (keynumber, key_type);
> +  *p++ = algo;
> 
>    for (i = 0; i < argc; i++)
>      {
> -      if (key_type == KEY_TYPE_RSA || i == 1)
> +      if (algo == PUBKEY_ALGO_RSA || i == 1)
>          {
>            nbits = count_bits (m[i], mlen[i]);
>            *p++ = nbits >> 8;
> @@ -924,70 +893,25 @@ send_key_data (ctrl_t ctrl, const char *name,
> 
> 
>  static void
> -get_ecc_key_parameters (int curve, int *r_n_bits, const char 
> **r_curve_oid)
> -{
> -  if (curve == CURVE_NIST_P256)
> -    {
> -      *r_n_bits = 256;
> -      *r_curve_oid = "1.2.840.10045.3.1.7";
> -    }
> -  else if (curve == CURVE_NIST_P384)
> -    {
> -      *r_n_bits = 384;
> -      *r_curve_oid = "1.3.132.0.34";
> -    }
> -  else if (curve == CURVE_NIST_P521)
> -    {
> -      *r_n_bits = 521;
> -      *r_curve_oid = "1.3.132.0.35";
> -    }
> -  else if (curve == CURVE_SEC_P256K1)
> -    {
> -      *r_n_bits = 256;
> -      *r_curve_oid = "1.3.132.0.10";
> -    }
> -  else if (curve == CURVE_ED25519)
> -    {
> -      *r_n_bits = 255;
> -      *r_curve_oid = "1.3.6.1.4.1.11591.15.1";
> -    }
> -  else
> -    {
> -      *r_n_bits = 0;
> -      *r_curve_oid = "1.3.6.1.4.1.11591.2.12242973"; /* 
> gnu.gnupg.badoid */
> -    }
> -}
> -
> -static void
> -send_key_attr (ctrl_t ctrl, app_t app, const char *keyword, int 
> number)
> +send_key_attr (ctrl_t ctrl, app_t app, const char *keyword, int keyno)
>  {
>    char buffer[200];
> -  int n_bits;
> -  const char *curve_oid;
> 
> -  assert (number >=0 && number < DIM(app->app_local->keyattr));
> +  assert (keyno >=0 && keyno < DIM(app->app_local->keyattr));
> 
> -  if (app->app_local->keyattr[number].key_type == KEY_TYPE_RSA)
> -    snprintf (buffer, sizeof buffer, "%d 1 %u %u %d",
> -              number+1,
> -              app->app_local->keyattr[number].rsa.n_bits,
> -              app->app_local->keyattr[number].rsa.e_bits,
> -              app->app_local->keyattr[number].rsa.format);
> -  else if (app->app_local->keyattr[number].key_type == KEY_TYPE_ECC)
> +  if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA)
> +    snprintf (buffer, sizeof buffer, "%d 1 rsa%u %u %d",
> +              keyno+1,
> +              app->app_local->keyattr[keyno].rsa.n_bits,
> +              app->app_local->keyattr[keyno].rsa.e_bits,
> +              app->app_local->keyattr[keyno].rsa.format);
> +  else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC)
>      {
> -      get_ecc_key_parameters 
> (app->app_local->keyattr[number].ecc.curve,
> -                              &n_bits, &curve_oid);
> -      snprintf (buffer, sizeof buffer, "%d %d %u %s",
> -                number+1,
> -                number==1? PUBKEY_ALGO_ECDH: PUBKEY_ALGO_ECDSA,
> -                n_bits, curve_oid);
> -    }
> -  else if (app->app_local->keyattr[number].key_type == KEY_TYPE_EDDSA)
> -    {
> -      get_ecc_key_parameters 
> (app->app_local->keyattr[number].eddsa.curve,
> -                              &n_bits, &curve_oid);
> -      snprintf (buffer, sizeof buffer, "%d 22 %u %s",
> -                number+1, n_bits, curve_oid);
> +      snprintf (buffer, sizeof buffer, "%d %d %s",
> +                keyno+1,
> +                app->app_local->keyattr[keyno].ecc.flags? 
> PUBKEY_ALGO_EDDSA:
> +                (keyno==1? PUBKEY_ALGO_ECDH: PUBKEY_ALGO_ECDSA),
> +                openpgp_oid_to_curve 
> (app->app_local->keyattr[keyno].ecc.oid));
>      }
>    else
>      snprintf (buffer, sizeof buffer, "0 0 UNKNOWN");
> @@ -1295,24 +1219,6 @@ retrieve_key_material (FILE *fp, const char 
> *hexkeyid,
>  #endif /*GNUPG_MAJOR_VERSION > 1*/
> 
> 
> -static const char *
> -get_curve_name (int curve)
> -{
> -  if (curve == CURVE_NIST_P256)
> -    return "NIST P-256";
> -  else if (curve == CURVE_NIST_P384)
> -    return "NIST P-384";
> -  else if (curve == CURVE_NIST_P521)
> -    return "NIST P-521";
> -  else if (curve == CURVE_SEC_P256K1)
> -    return "secp256k1";
> -  else if (curve == CURVE_ED25519)
> -    return "Ed25519";
> -  else
> -    return "unknown";
> -}
> -
> -
>  /* Get the public key for KEYNO and store it as an S-expresion with
>     the APP handle.  On error that field gets cleared.  If we already
>     know about the public key we will just return.  Note that this does
> @@ -1480,7 +1386,9 @@ get_public_key (app_t app, int keyno)
>        goto leave;
>      }
>    /* Prepend numbers with a 0 if needed.  */
> -  if (app->app_local->keyattr[keyno].key_type != KEY_TYPE_EDDSA
> +  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].ecc.flags))
>        && mlen && (*m & 0x80))
>      {
>        *mbuf = 0;
> @@ -1526,35 +1434,12 @@ get_public_key (app_t app, int keyno)
>      }
>    else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC)
>      {
> -      const char *curve_name
> -        = get_curve_name (app->app_local->keyattr[keyno].ecc.curve);
> -
>        err = gcry_sexp_build (&s_pkey, NULL,
> -                             "(public-key(ecc(curve%s)(q%b)))",
> -                             curve_name, (int)mlen, mbuf);
> -      if (err)
> -        goto leave;
> -
> -      len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
> -
> -      keybuf = xtrymalloc (len);
> -      if (!keybuf)
> -        {
> -          gcry_sexp_release (s_pkey);
> -          err = gpg_error_from_syserror ();
> -          goto leave;
> -        }
> -      gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, keybuf, len);
> -      gcry_sexp_release (s_pkey);
> -    }
> -  else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_EDDSA)
> -    {
> -      const char *curve_name
> -        = get_curve_name (app->app_local->keyattr[keyno].eddsa.curve);
> -
> -      err = gcry_sexp_build (&s_pkey, NULL,
> -                             "(public-key(ecc(curve%s)(flags 
> eddsa)(q%b)))",
> -                             curve_name, (int)mlen, mbuf);
> +                             "(public-key(ecc(curve%s)%s(q%b)))",
> +                             openpgp_oid_to_curve
> (app->app_local->keyattr[keyno].ecc.oid),
> +                             app->app_local->keyattr[keyno].ecc.flags?
> +                             "(flags eddsa)" : "",
> +                             (int)mlen, mbuf);
>        if (err)
>          goto leave;
> 
> @@ -3256,7 +3141,7 @@ rsa_writekey (app_t app, gpg_error_t
> (*pincb)(void*, const char *, char **),
>        goto leave;
>      }
> 
> -  err = store_fpr (app, keyno, created_at, fprbuf, KEY_TYPE_RSA,
> +  err = store_fpr (app, keyno, created_at, fprbuf, PUBKEY_ALGO_RSA,
>                     rsa_n, rsa_n_len, rsa_e, rsa_e_len);
>    if (err)
>      goto leave;
> @@ -3280,11 +3165,10 @@ ecc_writekey (app_t app, gpg_error_t
> (*pincb)(void*, const char *, char **),
>    const unsigned char *ecc_q = NULL;
>    const unsigned char *ecc_d = NULL;
>    size_t ecc_q_len, ecc_d_len;
> -  unsigned char *template = NULL;
> -  size_t template_len;
> -  unsigned char fprbuf[20];
>    u32 created_at = 0;
> -  int curve = CURVE_UNKNOWN;
> +  const char *oidstr = NULL;
> +  int flag_eddsa = 0;
> +  int algo;
> 
>    /* (private-key(ecc(curve%s)(q%m)(d%m))(created-at%d)):
>       curve = "NIST P-256" */
> @@ -3306,21 +3190,30 @@ ecc_writekey (app_t app, gpg_error_t
> (*pincb)(void*, const char *, char **),
> 
>        if (tok && toklen == 5 && !memcmp (tok, "curve", 5))
>          {
> +          unsigned char *curve;
> +
>            if ((err = parse_sexp (&buf, &buflen, &depth, &tok, 
> &toklen)))
>              goto leave;
> 
> -          if (tok && toklen == 10 && !memcmp (tok, "NIST P-256", 10))
> -            curve = CURVE_NIST_P256;
> -          else if (tok && toklen == 9 && !memcmp (tok, "secp256k1", 
> 9))
> -            curve = CURVE_SEC_P256K1;
> -          else if (tok && toklen == 7 && !memcmp (tok, "Ed25519", 7))
> -            curve = CURVE_ED25519;
> -          else
> +          curve = xtrymalloc (toklen+1);
> +          if (!curve)
>              {
> -              log_error (_("unsupported curve\n"));
> -              err = gpg_error (GPG_ERR_INV_VALUE);
> +              err = gpg_error_from_syserror ();
>                goto leave;
>              }
> +
> +          memcpy (curve, tok, toklen);
> +          curve[toklen] = 0;
> +          oidstr = openpgp_curve_to_oid (curve, NULL);
> +          xfree (curve);
> +        }
> +      else if (tok && toklen == 5 && !memcmp (tok, "flags", 5))
> +        {
> +          if ((err = parse_sexp (&buf, &buflen, &depth, &tok, 
> &toklen)))
> +            goto leave;
> +
> +          if (tok && toklen == 5 && !memcmp (tok, "eddsa", 5))
> +            flag_eddsa = 1;
>          }
>        else if (tok && toklen == 1)
>          {
> @@ -3340,7 +3233,7 @@ ecc_writekey (app_t app, gpg_error_t
> (*pincb)(void*, const char *, char **),
>              }
>            if ((err = parse_sexp (&buf, &buflen, &depth, &tok, 
> &toklen)))
>              goto leave;
> -          if (tok && buf2 && curve != CURVE_ED25519)
> +          if (tok && buf2 && !flag_eddsa)
>              /* It's MPI.  Strip off leading zero bytes and save. */
>              for (;toklen && !*tok; toklen--, tok++)
>                ;
> @@ -3391,12 +3284,33 @@ ecc_writekey (app_t app, gpg_error_t
> (*pincb)(void*, const char *, char **),
> 
>    /* Check that we have all parameters and that they match the card
>       description. */
> +  if (!oidstr)
> +    {
> +      log_error (_("unsupported curve\n"));
> +      err = gpg_error (GPG_ERR_INV_VALUE);
> +      goto leave;
> +    }
>    if (!created_at)
>      {
>        log_error (_("creation timestamp missing\n"));
>        err = gpg_error (GPG_ERR_INV_VALUE);
>        goto leave;
>      }
> +  if (flag_eddsa && keyno != 1)
> +    algo = PUBKEY_ALGO_EDDSA;
> +  else if (keyno == 1)
> +    algo = PUBKEY_ALGO_ECDH;
> +  else
> +    algo = PUBKEY_ALGO_ECDSA;
> +
> +  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.flags != flag_eddsa)
> +    {
> +      log_error ("key attribute on card doesn't match\n");
> +      err = gpg_error (GPG_ERR_INV_VALUE);
> +      goto leave;
> +    }
> 
>    if (opt.verbose)
>      log_info ("ECC private key size is %u bytes\n", (unsigned 
> int)ecc_d_len);
> @@ -3411,6 +3325,8 @@ ecc_writekey (app_t app, gpg_error_t
> (*pincb)(void*, const char *, char **),
>      {
>        /* Build the private key template as described in section 
> 4.3.3.7 of
>           the OpenPGP card specs version 2.0.  */
> +      unsigned char *template;
> +      size_t template_len;
>        int exmode;
> 
>        err = build_ecc_privkey_template (app, keyno,
> @@ -3422,7 +3338,10 @@ ecc_writekey (app_t app, gpg_error_t
> (*pincb)(void*, const char *, char **),
>        /* Prepare for storing the key.  */
>        err = verify_chv3 (app, pincb, pincb_arg);
>        if (err)
> -        goto leave;
> +        {
> +          xfree (template);
> +          goto leave;
> +        }
> 
>        /* Store the key. */
>        if (app->app_local->cardcap.ext_lc_le && template_len > 254)
> @@ -3433,32 +3352,41 @@ ecc_writekey (app_t app, gpg_error_t
> (*pincb)(void*, const char *, char **),
>          exmode = 0;
>        err = iso7816_put_data_odd (app->slot, exmode, 0x3fff,
>                                    template, template_len);
> +      xfree (template);
>      }
>    else
> -    return gpg_error (GPG_ERR_NOT_SUPPORTED);
> +    err = gpg_error (GPG_ERR_NOT_SUPPORTED);
> 
>    if (err)
>      {
>        log_error (_("failed to store the key: %s\n"), gpg_strerror 
> (err));
>        goto leave;
>      }
> +  else
> +    {
> +      gcry_mpi_t oid;
> +      const unsigned char *oidbuf;
> +      size_t oid_len;
> +      unsigned char fprbuf[20];
> 
> -  err = store_fpr (app, keyno, created_at, fprbuf,
> -                   curve == CURVE_ED25519 ? KEY_TYPE_EDDSA : 
> KEY_TYPE_ECC,
> -                   curve == CURVE_ED25519 ?
> -                   "\x09\x2b\x06\x01\x04\x01\xda\x47\x0f\x01"
> -                   : curve == CURVE_NIST_P256 ?
> -                   "\x08\x2a\x86\x48\xce\x3d\x03\x01\x07"
> -                   : "\x05\x2b\x81\x04\x00\x0a",
> -                   (size_t)(curve == CURVE_ED25519 ? 10
> -                            : curve == CURVE_NIST_P256? 9 : 6),
> -                   ecc_q, ecc_q_len, "\x03\x01\x08\x07", (size_t)4);
> -  if (err)
> -    goto leave;
> +      err = openpgp_oid_from_str (oidstr, &oid);
> +      if (err)
> +        goto leave;
> 
> +      oidbuf = gcry_mpi_get_opaque (oid, &oid_len);
> +      if (!oidbuf)
> +        {
> +          err = gpg_error_from_syserror ();
> +          gcry_mpi_release (oid);
> +          goto leave;
> +        }
> +      err = store_fpr (app, keyno, created_at, fprbuf, algo,
> +                   oidbuf, oid_len, ecc_q, ecc_q_len,
> +                   "\x03\x01\x08\x07", (size_t)4);
> +      gcry_mpi_release (oid);
> +    }
> 
>   leave:
> -  xfree (template);
>    return err;
>  }
> 
> @@ -3661,7 +3589,7 @@ do_genkey (app_t app, ctrl_t ctrl,  const char
> *keynostr, unsigned int flags,
>    send_status_info (ctrl, "KEY-CREATED-AT",
>                      numbuf, (size_t)strlen(numbuf), NULL, 0);
> 
> -  rc = store_fpr (app, keyno, (u32)created_at, fprbuf, KEY_TYPE_RSA,
> +  rc = store_fpr (app, keyno, (u32)created_at, fprbuf, 
> PUBKEY_ALGO_RSA,
>                    m, mlen, e, elen);
>    if (rc)
>      goto leave;
> @@ -4014,18 +3942,21 @@ do_auth (app_t app, const char *keyidstr,
>        && indatalen > 101) /* For a 2048 bit key. */
>      return gpg_error (GPG_ERR_INV_VALUE);
> 
> -  if (app->app_local->keyattr[2].key_type == KEY_TYPE_ECC
> -      && (indatalen == 51 || indatalen == 67 || indatalen == 83))
> +  if (app->app_local->keyattr[2].key_type == KEY_TYPE_ECC)
>      {
> -      const char *p = (const char *)indata + 19;
> -      indata = p;
> -      indatalen -= 19;
> -    }
> -  else if (app->app_local->keyattr[2].key_type == KEY_TYPE_EDDSA)
> -    {
> -      const char *p = (const char *)indata + 15;
> -      indata = p;
> -      indatalen -= 15;
> +      if (!app->app_local->keyattr[2].ecc.flags
> +          && (indatalen == 51 || indatalen == 67 || indatalen == 83))
> +        {
> +          const char *p = (const char *)indata + 19;
> +          indata = p;
> +          indatalen -= 19;
> +        }
> +      else
> +        {
> +          const char *p = (const char *)indata + 15;
> +          indata = p;
> +          indatalen -= 15;
> +        }
>      }
> 
>    /* Check whether an OpenPGP card of any version has been requested. 
> */
> @@ -4429,25 +4360,25 @@ parse_historical (struct app_local_s *apploc,
>  }
> 
> 
> -static int
> -parse_ecc_curve (const unsigned char *buffer, size_t buflen)
> +static const char *
> +ecc_oid (unsigned char *buf, size_t buflen)
>  {
> -  int curve;
> +  gcry_mpi_t oid;
> +  char *oidstr;
> +  const char *result;
> 
> -  if (buflen == 5 && buffer[5] == 0x22)
> -    curve = CURVE_NIST_P384;
> -  else if (buflen == 5 && buffer[5] == 0x23)
> -    curve = CURVE_NIST_P521;
> -  else if (buflen == 8)
> -    curve = CURVE_NIST_P256;
> -  else if (buflen == 5 && buffer[5] == 0x0a)
> -    curve = CURVE_SEC_P256K1;
> -  else if (buflen == 9)
> -    curve = CURVE_ED25519;
> -  else
> -    curve = CURVE_UNKNOWN;
> +  oid = gcry_mpi_set_opaque (NULL, buf, buflen * 8);
> +  if (!oid)
> +    return NULL;
> 
> -  return curve;
> +  oidstr = openpgp_oid_to_str (oid);
> +  gcry_mpi_release (oid);
> +  if (!oidstr)
> +    return NULL;
> +
> +  result = openpgp_curve_to_oid (oidstr, NULL);
> +  xfree (oidstr);
> +  return result;
>  }
> 
> 
> @@ -4505,25 +4436,16 @@ parse_algorithm_attribute (app_t app, int 
> keyno)
>             app->app_local->keyattr[keyno].rsa.format == RSA_CRT?  
> "crt"  :
>             app->app_local->keyattr[keyno].rsa.format == 
> RSA_CRT_N?"crt+n":"?");
>      }
> -  else if (*buffer == PUBKEY_ALGO_ECDH || *buffer == 
> PUBKEY_ALGO_ECDSA)
> +  else if (*buffer == PUBKEY_ALGO_ECDH || *buffer == PUBKEY_ALGO_ECDSA
> +           || *buffer == PUBKEY_ALGO_EDDSA)
>      {
>        app->app_local->keyattr[keyno].key_type = KEY_TYPE_ECC;
> -      app->app_local->keyattr[keyno].ecc.curve
> -        = parse_ecc_curve (buffer + 1, buflen - 1);
> +      app->app_local->keyattr[keyno].ecc.oid = ecc_oid (buffer + 1,
> buflen - 1);
> +      app->app_local->keyattr[keyno].ecc.flags = (*buffer ==
> PUBKEY_ALGO_EDDSA);
>        if (opt.verbose)
>          log_printf
> -          ("ECC, curve=%s\n",
> -           get_curve_name (app->app_local->keyattr[keyno].ecc.curve));
> -    }
> -  else if (*buffer == PUBKEY_ALGO_EDDSA)
> -    {
> -      app->app_local->keyattr[keyno].key_type = KEY_TYPE_EDDSA;
> -      app->app_local->keyattr[keyno].eddsa.curve
> -        = parse_ecc_curve (buffer + 1, buflen - 1);
> -      if (opt.verbose)
> -        log_printf
> -          ("EdDSA, curve=%s\n",
> -           get_curve_name 
> (app->app_local->keyattr[keyno].eddsa.curve));
> +          ("ECC, curve=%s%s\n", 
> app->app_local->keyattr[keyno].ecc.oid,
> +           app->app_local->keyattr[keyno].ecc.flags ? " (eddsa)": "");
>      }
>    else if (opt.verbose)
>      log_printhex ("", buffer, buflen);

-- 
Bertrand



More information about the Gnupg-devel mailing list