From 44676819f2873705b78849e7b2fd22214b691642 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 19 May 2020 14:30:24 +0200 Subject: [PATCH] sm: Create ECC certificates with AKI and SKI by default. * sm/certreqgen.c (create_request): Create AKI and SKI by default. -- GnuPG-bug-id: 4098 Signed-off-by: Werner Koch --- doc/gpgsm.texi | 20 +++++- sm/certreqgen.c | 158 ++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 145 insertions(+), 33 deletions(-) diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi index 4298e4350..0579be3ba 100644 --- a/doc/gpgsm.texi +++ b/doc/gpgsm.texi @@ -1099,10 +1099,12 @@ General Parameters: @item Key-Type: @var{algo} Starts a new parameter block by giving the type of the primary key. The algorithm must be capable of signing. This is a required -parameter. The only supported value for @var{algo} is @samp{rsa}. +parameter. The supported values for @var{algo} are @samp{rsa}, +@samp{ecdsa}, and @samp{eddsa}. @item Key-Length: @var{nbits} -The requested length of a generated key in bits. Defaults to 3072. +The requested length of a generated key in bits. Defaults to +3072. The value is ignored for ECC algorithms. @item Key-Grip: @var{hexstring} This is optional and used to generate a CSR or certificate for an @@ -1175,6 +1177,20 @@ algorithms are: @samp{sha1}, @samp{sha256}, @samp{sha384} and @samp{sha512}; they may also be specified with uppercase letters. The default is @samp{sha256}. +@item Authority-Key-Id: @var{hexstring} +Insert the decoded value of @var{hexstring} as authorityKeyIdentifier. +If this is not given and an ECC algorithm is used the public part of +the certified public key is used as authorityKeyIdentifier. To +inhibit any authorityKeyIdentifier use the special value @code{none} +for @var{hexstring}. + +@item Subject-Key-Id: @var{hexstring} +Insert the decoded value of @var{hexstring} as subjectKeyIdentifier. +If this is not given and an ECC algorithm is used the public part of +the signing key is used as authorityKeyIdentifier. To inhibit any +subjectKeyIdentifier use the special value @code{none} for +@var{hexstring}. + @end table @c ******************************************* diff --git a/sm/certreqgen.c b/sm/certreqgen.c index e54569ac8..1dd456452 100644 --- a/sm/certreqgen.c +++ b/sm/certreqgen.c @@ -630,7 +630,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, /* Check the optional AuthorityKeyId. */ string = get_parameter_value (para, pAUTHKEYID, 0); - if (string) + if (string && strcmp (string, "none")) { for (s=string, i=0; hexdigitp (s); s++, i++) ; @@ -645,7 +645,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, /* Check the optional SubjectKeyId. */ string = get_parameter_value (para, pSUBJKEYID, 0); - if (string) + if (string && strcmp (string, "none")) { for (s=string, i=0; hexdigitp (s); s++, i++) ; @@ -838,13 +838,22 @@ create_request (ctrl_t ctrl, int mdalgo; membuf_t tbsbuffer; membuf_t *tbsmb = NULL; + size_t publiclen; + size_t sigkeylen; + int publicpkalgo; /* The gcrypt public key algo of the public key. */ + int sigkeypkalgo; /* The gcrypt public key algo of the signing key. */ err = ksba_certreq_new (&cr); if (err) return err; - len = gcry_sexp_canon_len (public, 0, NULL, NULL); - if (get_pk_algo_from_canon_sexp (public, len) == GCRY_PK_EDDSA) + publiclen = gcry_sexp_canon_len (public, 0, NULL, NULL); + sigkeylen = sigkey? gcry_sexp_canon_len (sigkey, 0, NULL, NULL) : 0; + + publicpkalgo = get_pk_algo_from_canon_sexp (public, publiclen); + sigkeypkalgo = sigkey? get_pk_algo_from_canon_sexp (public, publiclen) : 0; + + if (publicpkalgo == GCRY_PK_EDDSA) { mdalgo = GCRY_MD_SHA512; md = NULL; /* We sign the data and not a hash. */ @@ -957,12 +966,10 @@ create_request (ctrl_t ctrl, } } - err = ksba_certreq_set_public_key (cr, public); if (err) { - log_error ("error setting the public key: %s\n", - gpg_strerror (err)); + log_error ("error setting the public key: %s\n", gpg_strerror (err)); rc = err; goto leave; } @@ -1158,15 +1165,17 @@ create_request (ctrl_t ctrl, given we set it to the public key to create a self-signed certificate. */ if (!sigkey) - sigkey = public; + { + sigkey = public; + sigkeylen = publiclen; + sigkeypkalgo = publicpkalgo; + } + /* Set the the digestinfo aka siginfo. */ { unsigned char *siginfo; - - err = transform_sigval (sigkey, - gcry_sexp_canon_len (sigkey, 0, NULL, NULL), - mdalgo, &siginfo, NULL); + err = transform_sigval (sigkey, sigkeylen, mdalgo, &siginfo, NULL); if (!err) { err = ksba_certreq_set_siginfo (cr, siginfo); @@ -1181,9 +1190,12 @@ create_request (ctrl_t ctrl, } } + /* Insert the AuthorityKeyId. */ string = get_parameter_value (para, pAUTHKEYID, 0); - if (string) + if (string && !strcmp (string, "none")) + ; /* Do not issue an AKI. */ + else if (string) { char *hexbuf; @@ -1209,20 +1221,69 @@ create_request (ctrl_t ctrl, hexbuf[2] = 0x80; /* Context tag for an implicit Octet string. */ hexbuf[3] = len; err = ksba_certreq_add_extension (cr, oidstr_authorityKeyIdentifier, - 0, - hexbuf, 4+len); + 0, hexbuf, 4+len); xfree (hexbuf); if (err) { - log_error ("error setting the authority-key-id: %s\n", + log_error ("error setting the AKI: %s\n", gpg_strerror (err)); + goto leave; + } + } + else if (publicpkalgo == GCRY_PK_EDDSA || publicpkalgo == GCRY_PK_ECC) + { + /* For EdDSA and ECC we add the public key as default identifier. */ + const unsigned char *q; + size_t qlen, derlen; + unsigned char *der; + + err = get_ecc_q_from_canon_sexp (public, publiclen, &q, &qlen); + if (err) + { + log_error ("error getting Q from public key: %s\n", gpg_strerror (err)); goto leave; } + if (publicpkalgo == GCRY_PK_EDDSA && qlen>32 && (qlen&1) && *q==0x40) + { + /* Skip our optional native encoding octet. */ + q++; + qlen--; + } + /* FIXME: For plain ECC we should better use a compressed + * point. That requires an updated Libgcrypt. Without that + * using nistp521 won't work due to the length check below. */ + if (qlen > 125) + { + err = gpg_error (GPG_ERR_TOO_LARGE); + goto leave; + } + derlen = 4 + qlen; + der = xtrymalloc (derlen); + if (!der) + { + err = gpg_error_from_syserror (); + goto leave; + } + der[0] = 0x30; /* Sequence */ + der[1] = qlen + 2; + der[2] = 0x80; /* Context tag for an implict Octet String. */ + der[3] = qlen; + memcpy (der+4, q, qlen); + err = ksba_certreq_add_extension (cr, oidstr_authorityKeyIdentifier, + 0, der, derlen); + xfree (der); + if (err) + { + log_error ("error setting the AKI: %s\n", gpg_strerror (err)); + goto leave; + } } /* Insert the SubjectKeyId. */ string = get_parameter_value (para, pSUBJKEYID, 0); - if (string) + if (string && !strcmp (string, "none")) + ; /* Do not issue an SKI. */ + else if (string) { char *hexbuf; @@ -1250,10 +1311,53 @@ create_request (ctrl_t ctrl, xfree (hexbuf); if (err) { - log_error ("error setting the subject-key-id: %s\n", + log_error ("error setting SKI: %s\n", gpg_strerror (err)); + goto leave; + } + } + else if (sigkeypkalgo == GCRY_PK_EDDSA || sigkeypkalgo == GCRY_PK_ECC) + { + /* For EdDSA and ECC we add the public key as default identifier. */ + const unsigned char *q; + size_t qlen, derlen; + unsigned char *der; + + err = get_ecc_q_from_canon_sexp (sigkey, sigkeylen, &q, &qlen); + if (err) + { + log_error ("error getting Q from signature key: %s\n", gpg_strerror (err)); goto leave; } + if (sigkeypkalgo == GCRY_PK_EDDSA && qlen>32 && (qlen&1) && *q==0x40) + { + /* Skip our optional native encoding octet. */ + q++; + qlen--; + } + if (qlen > 127) + { + err = gpg_error (GPG_ERR_TOO_LARGE); + goto leave; + } + derlen = 2 + qlen; + der = xtrymalloc (derlen); + if (!der) + { + err = gpg_error_from_syserror (); + goto leave; + } + der[0] = 0x04; /* Octet String */ + der[1] = qlen; + memcpy (der+2, q, qlen); + err = ksba_certreq_add_extension (cr, oidstr_subjectKeyIdentifier, 0, + der, derlen); + xfree (der); + if (err) + { + log_error ("error setting the SKI: %s\n", gpg_strerror (err)); + goto leave; + } } /* Insert additional extensions. */ @@ -1329,7 +1433,6 @@ create_request (ctrl_t ctrl, if (stopreason == KSBA_SR_NEED_SIG) { gcry_sexp_t s_pkey; - size_t n; unsigned char grip[20]; char hexgrip[41]; unsigned char *sigval, *newsigval; @@ -1337,14 +1440,7 @@ create_request (ctrl_t ctrl, void *tbsdata; size_t tbsdatalen; - n = gcry_sexp_canon_len (sigkey, 0, NULL, NULL); - if (!n) - { - log_error ("libksba did not return a proper S-Exp\n"); - rc = gpg_error (GPG_ERR_BUG); - goto leave; - } - rc = gcry_sexp_sscan (&s_pkey, NULL, (const char*)sigkey, n); + rc = gcry_sexp_sscan (&s_pkey, NULL, (const char*)sigkey, sigkeylen); if (rc) { log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc)); @@ -1360,8 +1456,9 @@ create_request (ctrl_t ctrl, gcry_sexp_release (s_pkey); bin2hex (grip, 20, hexgrip); - log_info ("about to sign the %s for key: &%s\n", - certmode? "certificate":"CSR", hexgrip); + if (!opt.quiet) + log_info ("about to sign the %s for key: &%s\n", + certmode? "certificate":"CSR", hexgrip); if (carddirect && !certmode) { @@ -1422,8 +1519,7 @@ create_request (ctrl_t ctrl, goto leave; } - err = transform_sigval (sigval, siglen, mdalgo, - &newsigval, NULL); + err = transform_sigval (sigval, siglen, mdalgo, &newsigval, NULL); xfree (sigval); if (!err) {