aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--scd/app-common.h2
-rw-r--r--scd/app-help.c54
-rw-r--r--scd/command.c62
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;
-
- rc = ksba_cert_new (&kc);
- if (rc)
- goto leave;
-
- 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);
+ else
+ log_error ("app_readkey failed: %s\n", gpg_strerror (rc));
+ if (!rc && pk && pklen)
+ rc = assuan_send_data (ctx, pk, pklen);
- leave:
- ksba_cert_release (kc);
xfree (cert);
+ xfree (pk);
+ xfree (line);
return rc;
}