From 96577e2e46e4c5b66a2685cb605e07be0a6a09a5 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 29 Apr 2021 16:05:19 +0200 Subject: [PATCH] scd: Rewrite READKEY to allow for compressed points. * scd/app-help.c (app_help_pubkey_from_cert): New. Taken from 2.3. * scd/command.c (cmd_readkey): Rewrite using new helper. -- Actually the readkey functions needs to return the uncompressed points but if there is no readkey function, like in app-p15.c, readcert is used and here we need to extract and the key and uncompress the point. Noet that the --advanced flag did not and still does not work if the key is fetched via readcert. Signed-off-by: Werner Koch --- scd/app-common.h | 2 ++ scd/app-help.c | 54 +++++++++++++++++++++++++++++++++++++++++ scd/command.c | 62 +++++++++++++++--------------------------------- 3 files changed, 75 insertions(+), 43 deletions(-) diff --git a/scd/app-common.h b/scd/app-common.h index 299465023..0265604c5 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -211,6 +211,8 @@ gpg_error_t app_help_get_keygrip_string_pk (const void *pk, size_t pklen, int *r_algo); gpg_error_t app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip, gcry_sexp_t *r_pkey, int *r_algo); +gpg_error_t app_help_pubkey_from_cert (const void *cert, size_t certlen, + unsigned char **r_pk, size_t *r_pklen); size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff); diff --git a/scd/app-help.c b/scd/app-help.c index 476eecf2f..f95928675 100644 --- a/scd/app-help.c +++ b/scd/app-help.c @@ -122,6 +122,60 @@ app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip, } +/* Get the public key from the binary encoded (CERT,CERTLEN). */ +gpg_error_t +app_help_pubkey_from_cert (const void *cert, size_t certlen, + unsigned char **r_pk, size_t *r_pklen) +{ + gpg_error_t err; + ksba_cert_t kc; + unsigned char *pk, *fixed_pk; + size_t pklen, fixed_pklen; + + *r_pk = NULL; + *r_pklen = 0; + + pk = NULL; /*(avoid cc warning)*/ + + err = ksba_cert_new (&kc); + if (err) + return err; + + err = ksba_cert_init_from_mem (kc, cert, certlen); + if (err) + goto leave; + + pk = ksba_cert_get_public_key (kc); + if (!pk) + { + err = gpg_error (GPG_ERR_NO_PUBKEY); + goto leave; + } + pklen = gcry_sexp_canon_len (pk, 0, NULL, &err); + + err = uncompress_ecc_q_in_canon_sexp (pk, pklen, &fixed_pk, &fixed_pklen); + if (err) + goto leave; + if (fixed_pk) + { + ksba_free (pk); pk = NULL; + pk = fixed_pk; + pklen = fixed_pklen; + } + + leave: + if (!err) + { + *r_pk = pk; + *r_pklen = pklen; + } + else + ksba_free (pk); + ksba_cert_release (kc); + return err; +} + + /* Given the SLOT and the File ID FID, return the length of the certificate contained in that file. Returns 0 if the file does not exists or does not contain a certificate. If R_CERTOFF is not diff --git a/scd/command.c b/scd/command.c index e1895c6e3..dd965a31b 100644 --- a/scd/command.c +++ b/scd/command.c @@ -513,9 +513,7 @@ cmd_readkey (assuan_context_t ctx, char *line) int rc; int advanced = 0; unsigned char *cert = NULL; - size_t ncert, n; - ksba_cert_t kc = NULL; - ksba_sexp_t p; + size_t ncert; unsigned char *pk; size_t pklen; @@ -526,60 +524,38 @@ cmd_readkey (assuan_context_t ctx, char *line) advanced = 1; line = skip_options (line); - line = xstrdup (line); /* Need a copy of the line. */ + /* If the application supports the READKEY function we use that. Otherwise we use the old way by extracting it from the certificate. */ rc = app_readkey (ctrl->app_ctx, ctrl, advanced, line, &pk, &pklen); if (!rc) - { /* Yeah, got that key - send it back. */ - rc = assuan_send_data (ctx, pk, pklen); - xfree (pk); - xfree (line); - line = NULL; - goto leave; - } - - if (gpg_err_code (rc) != GPG_ERR_UNSUPPORTED_OPERATION) - log_error ("app_readkey failed: %s\n", gpg_strerror (rc)); - else + ; /* Yeah, got that key - send it back. */ + else if (gpg_err_code (rc) == GPG_ERR_UNSUPPORTED_OPERATION + || gpg_err_code (rc) == GPG_ERR_NOT_FOUND) { + /* Fall back to certificate reading. */ rc = app_readcert (ctrl->app_ctx, ctrl, line, &cert, &ncert); if (rc) log_error ("app_readcert failed: %s\n", gpg_strerror (rc)); + else + { + rc = app_help_pubkey_from_cert (cert, ncert, &pk, &pklen); + if (rc) + log_error ("failed to parse the certificate: %s\n", + gpg_strerror (rc)); + } } - xfree (line); - line = NULL; - if (rc) - goto leave; + else + log_error ("app_readkey failed: %s\n", gpg_strerror (rc)); - rc = ksba_cert_new (&kc); - if (rc) - goto leave; + if (!rc && pk && pklen) + rc = assuan_send_data (ctx, pk, pklen); - rc = ksba_cert_init_from_mem (kc, cert, ncert); - if (rc) - { - log_error ("failed to parse the certificate: %s\n", gpg_strerror (rc)); - goto leave; - } - - p = ksba_cert_get_public_key (kc); - if (!p) - { - rc = gpg_error (GPG_ERR_NO_PUBKEY); - goto leave; - } - - n = gcry_sexp_canon_len (p, 0, NULL, NULL); - rc = assuan_send_data (ctx, p, n); - xfree (p); - - - leave: - ksba_cert_release (kc); xfree (cert); + xfree (pk); + xfree (line); return rc; }