From 6a37240cf279b27cddcc88de93098c55f3f26701 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 20 May 2022 13:43:08 +0900 Subject: [PATCH] agent: Move confirmation handling into findkey.c. * agent/agent.h (divert_tpm2_pksign, divert_tpm2_pkdecrypt): Fix API. (divert_pksign, divert_pkdecrypt): Likewise. * agent/divert-scd.c (ask_for_card): Remove. (divert_pksign, divert_pkdecrypt): Don't call ask_for_card. * agent/divert-tpm2.c (divert_tpm2_pksign, divert_tpm2_pkdecrypt): Remove DESC_TEXT argument. * agent/findkey.c (prompt_for_card): New (was: ask_for_card). (agent_key_from_file): Call prompt_for_card when it's a key on card. * agent/pkdecrypt.c (agent_pkdecrypt): Follow the change of API. * agent/pksign.c (agent_pksign_do): Likewise. -- Signed-off-by: NIIBE Yutaka --- agent/agent.h | 19 +++--- agent/divert-scd.c | 146 ++++---------------------------------------- agent/divert-tpm2.c | 7 +-- agent/findkey.c | 126 ++++++++++++++++++++++++++++++++++++-- agent/pkdecrypt.c | 6 +- agent/pksign.c | 12 +--- 6 files changed, 151 insertions(+), 165 deletions(-) diff --git a/agent/agent.h b/agent/agent.h index 4ee8e40c5..f1c9b83b6 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -593,11 +593,11 @@ void agent_reload_trustlist (void); /*-- divert-tpm2.c --*/ #ifdef HAVE_LIBTSS -int divert_tpm2_pksign (ctrl_t ctrl, const char *desc_text, +int divert_tpm2_pksign (ctrl_t ctrl, const unsigned char *digest, size_t digestlen, int algo, const unsigned char *shadow_info, unsigned char **r_sig, size_t *r_siglen); -int divert_tpm2_pkdecrypt (ctrl_t ctrl, const char *desc_text, +int divert_tpm2_pkdecrypt (ctrl_t ctrl, const unsigned char *cipher, const unsigned char *shadow_info, char **r_buf, size_t *r_len, int *r_padding); @@ -605,25 +605,25 @@ int divert_tpm2_writekey (ctrl_t ctrl, const unsigned char *grip, gcry_sexp_t s_skey); #else /*!HAVE_LIBTSS*/ static inline int -divert_tpm2_pksign (ctrl_t ctrl, const char *desc_text, +divert_tpm2_pksign (ctrl_t ctrl, const unsigned char *digest, size_t digestlen, int algo, const unsigned char *shadow_info, unsigned char **r_sig, size_t *r_siglen) { - (void)ctrl; (void)desc_text; (void)digest; (void)digestlen; + (void)ctrl; (void)digest; (void)digestlen; (void)algo; (void)shadow_info; (void)r_sig; (void)r_siglen; return gpg_error (GPG_ERR_NOT_SUPPORTED); } static inline int -divert_tpm2_pkdecrypt (ctrl_t ctrl, const char *desc_text, +divert_tpm2_pkdecrypt (ctrl_t ctrl, const unsigned char *cipher, const unsigned char *shadow_info, char **r_buf, size_t *r_len, int *r_padding) { - (void)ctrl; (void)desc_text; (void)cipher; (void)shadow_info; + (void)ctrl; (void)cipher; (void)shadow_info; (void)r_buf; (void)r_len; (void)r_padding; return gpg_error (GPG_ERR_NOT_SUPPORTED); } @@ -639,15 +639,14 @@ divert_tpm2_writekey (ctrl_t ctrl, const unsigned char *grip, /*-- divert-scd.c --*/ -int divert_pksign (ctrl_t ctrl, const char *desc_text, +int divert_pksign (ctrl_t ctrl, const unsigned char *grip, const unsigned char *digest, size_t digestlen, int algo, - const unsigned char *shadow_info, unsigned char **r_sig, + unsigned char **r_sig, size_t *r_siglen); -int divert_pkdecrypt (ctrl_t ctrl, const char *desc_text, +int divert_pkdecrypt (ctrl_t ctrl, const unsigned char *grip, const unsigned char *cipher, - const unsigned char *shadow_info, char **r_buf, size_t *r_len, int *r_padding); int divert_generic_cmd (ctrl_t ctrl, const char *cmdline, void *assuan_context); diff --git a/agent/divert-scd.c b/agent/divert-scd.c index 273f3a869..ed0173ea1 100644 --- a/agent/divert-scd.c +++ b/agent/divert-scd.c @@ -32,113 +32,6 @@ #include "../common/sexp-parse.h" -static gpg_error_t -ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, - const unsigned char *grip, char **r_kid) -{ - char *serialno; - char *desc; - char *want_sn; - int len; - gpg_error_t err; - char hexgrip[41]; - - *r_kid = NULL; - bin2hex (grip, 20, hexgrip); - - if (shadow_info) - { - err = parse_shadow_info (shadow_info, &want_sn, NULL, NULL); - if (err) - return err; - } - else - want_sn = NULL; - - len = want_sn? strlen (want_sn) : 0; - if (len == 32 && !strncmp (want_sn, "D27600012401", 12)) - { - /* This is an OpenPGP card - reformat */ - if (!strncmp (want_sn+16, "0006", 4)) - { - /* This is a Yubikey. Print the s/n as it would be printed - * on Yubikey 5. Example: D2760001240100000006120808620000 - * mmmm^^^^^^^^ */ - unsigned long sn; - - sn = atoi_4 (want_sn+20) * 10000; - sn += atoi_4 (want_sn+24); - snprintf (want_sn, 32, "%lu %03lu %03lu", - (sn/1000000ul), (sn/1000ul % 1000ul), (sn % 1000ul)); - } - else /* Default is the Zeitcontrol card print format. */ - { - memmove (want_sn, want_sn+16, 4); - want_sn[4] = ' '; - memmove (want_sn+5, want_sn+20, 8); - want_sn[13] = 0; - } - } - else if (len == 20 && want_sn[19] == '0') - { - /* We assume that a 20 byte serial number is a standard one - * which has the property to have a zero in the last nibble (Due - * to BCD representation). We don't display this '0' because it - * may confuse the user. */ - want_sn[19] = 0; - } - - for (;;) - { - /* Scan device(s), and check if key for GRIP is available. */ - err = agent_card_serialno (ctrl, &serialno, NULL); - if (!err) - { - struct card_key_info_s *keyinfo; - - xfree (serialno); - err = agent_card_keyinfo (ctrl, hexgrip, 0, &keyinfo); - if (!err) - { - /* Key for GRIP found, use it directly. */ - agent_card_free_keyinfo (keyinfo); - xfree (want_sn); - if ((*r_kid = xtrystrdup (hexgrip))) - return 0; - else - return gpg_error_from_syserror (); - } - } - - if (!want_sn) - ; /* No shadow info so we can't ask; ERR is already set. */ - else if (asprintf (&desc, - "%s:%%0A%%0A" - " %s", - L_("Please insert the card with serial number"), - want_sn) < 0) - { - err = out_of_core (); - } - else - { - err = agent_get_confirmation (ctrl, desc, NULL, NULL, 0); - if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK && - gpg_err_code (err) == GPG_ERR_NO_PIN_ENTRY) - err = gpg_error (GPG_ERR_CARD_NOT_PRESENT); - - xfree (desc); - } - - if (err) - { - xfree (want_sn); - return err; - } - } -} - - /* Put the DIGEST into an DER encoded container and return it in R_VAL. */ static int encode_md_for_card (const unsigned char *digest, size_t digestlen, int algo, @@ -426,44 +319,37 @@ getpin_cb (void *opaque, const char *desc_text, const char *info, /* This function is used when a sign operation has been diverted to a - * smartcard. DESC_TEXT is the original text for a prompt has send by - * gpg to gpg-agent. + * smartcard. * * Note: If SHADOW_INFO is NULL the user can't be asked to insert the * card, we simply try to use an inserted card with the given keygrip. * * FIXME: Explain the other args. */ int -divert_pksign (ctrl_t ctrl, const char *desc_text, const unsigned char *grip, +divert_pksign (ctrl_t ctrl, const unsigned char *grip, const unsigned char *digest, size_t digestlen, int algo, - const unsigned char *shadow_info, unsigned char **r_sig, + unsigned char **r_sig, size_t *r_siglen) { int rc; - char *kid; + char hexgrip[41]; size_t siglen; unsigned char *sigval = NULL; - (void)desc_text; - - rc = ask_for_card (ctrl, shadow_info, grip, &kid); - if (rc) - return rc; - /* Note that the KID may be an keyref or a keygrip. The signing - * functions handle both. */ + bin2hex (grip, 20, hexgrip); if (!algo) { /* This is the PureEdDSA case. (DIGEST,DIGESTLEN) this the * entire data which will be signed. */ - rc = agent_card_pksign (ctrl, kid, getpin_cb, ctrl, NULL, + rc = agent_card_pksign (ctrl, hexgrip, getpin_cb, ctrl, NULL, 0, digest, digestlen, &sigval, &siglen); } else if (algo == MD_USER_TLS_MD5SHA1) { int save = ctrl->use_auth_call; ctrl->use_auth_call = 1; - rc = agent_card_pksign (ctrl, kid, getpin_cb, ctrl, NULL, + rc = agent_card_pksign (ctrl, hexgrip, getpin_cb, ctrl, NULL, algo, digest, digestlen, &sigval, &siglen); ctrl->use_auth_call = save; } @@ -475,7 +361,7 @@ divert_pksign (ctrl_t ctrl, const char *desc_text, const unsigned char *grip, rc = encode_md_for_card (digest, digestlen, algo, &data, &ndata); if (!rc) { - rc = agent_card_pksign (ctrl, kid, getpin_cb, ctrl, NULL, + rc = agent_card_pksign (ctrl, hexgrip, getpin_cb, ctrl, NULL, algo, data, ndata, &sigval, &siglen); xfree (data); } @@ -487,8 +373,6 @@ divert_pksign (ctrl_t ctrl, const char *desc_text, const unsigned char *grip, *r_siglen = siglen; } - xfree (kid); - return rc; } @@ -498,14 +382,13 @@ divert_pksign (ctrl_t ctrl, const char *desc_text, const unsigned char *grip, allocated buffer in R_BUF. The padding information is stored at R_PADDING with -1 for not known. */ int -divert_pkdecrypt (ctrl_t ctrl, const char *desc_text, +divert_pkdecrypt (ctrl_t ctrl, const unsigned char *grip, const unsigned char *cipher, - const unsigned char *shadow_info, char **r_buf, size_t *r_len, int *r_padding) { int rc; - char *kid; + char hexgrip[41]; const unsigned char *s; size_t n; int depth; @@ -514,7 +397,7 @@ divert_pkdecrypt (ctrl_t ctrl, const char *desc_text, char *plaintext; size_t plaintextlen; - (void)desc_text; + bin2hex (grip, 20, hexgrip); *r_padding = -1; s = cipher; @@ -591,11 +474,7 @@ divert_pkdecrypt (ctrl_t ctrl, const char *desc_text, ciphertext = s; ciphertextlen = n; - rc = ask_for_card (ctrl, shadow_info, grip, &kid); - if (rc) - return rc; - - rc = agent_card_pkdecrypt (ctrl, kid, getpin_cb, ctrl, NULL, + rc = agent_card_pkdecrypt (ctrl, hexgrip, getpin_cb, ctrl, NULL, ciphertext, ciphertextlen, &plaintext, &plaintextlen, r_padding); if (!rc) @@ -603,7 +482,6 @@ divert_pkdecrypt (ctrl_t ctrl, const char *desc_text, *r_buf = plaintext; *r_len = plaintextlen; } - xfree (kid); return rc; } diff --git a/agent/divert-tpm2.c b/agent/divert-tpm2.c index 0741c6847..4cae66218 100644 --- a/agent/divert-tpm2.c +++ b/agent/divert-tpm2.c @@ -13,12 +13,11 @@ #include "../common/sexp-parse.h" int -divert_tpm2_pksign (ctrl_t ctrl, const char *desc_text, +divert_tpm2_pksign (ctrl_t ctrl, const unsigned char *digest, size_t digestlen, int algo, const unsigned char *shadow_info, unsigned char **r_sig, size_t *r_siglen) { - (void)desc_text; (void)algo; return agent_tpm2d_pksign(ctrl, digest, digestlen, shadow_info, r_sig, r_siglen); @@ -76,7 +75,7 @@ divert_tpm2_writekey (ctrl_t ctrl, const unsigned char *grip, } int -divert_tpm2_pkdecrypt (ctrl_t ctrl, const char *desc_text, +divert_tpm2_pkdecrypt (ctrl_t ctrl, const unsigned char *cipher, const unsigned char *shadow_info, char **r_buf, size_t *r_len, int *r_padding) @@ -86,8 +85,6 @@ divert_tpm2_pkdecrypt (ctrl_t ctrl, const char *desc_text, *r_padding = -1; - (void)desc_text; - s = cipher; if (*s != '(') return gpg_error (GPG_ERR_INV_SEXP); diff --git a/agent/findkey.c b/agent/findkey.c index 2612383b5..eadf283d3 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -961,6 +961,112 @@ remove_key_file (const unsigned char *grip) } +/* + * Prompt a user the card insertion, when it's not available yet. + */ +static gpg_error_t +prompt_for_card (ctrl_t ctrl, const unsigned char *shadow_info, + const unsigned char *grip) +{ + char *serialno; + char *desc; + char *want_sn; + int len; + gpg_error_t err; + char hexgrip[41]; + + bin2hex (grip, 20, hexgrip); + + if (shadow_info) + { + err = parse_shadow_info (shadow_info, &want_sn, NULL, NULL); + if (err) + return err; + } + else + want_sn = NULL; + + len = want_sn? strlen (want_sn) : 0; + if (len == 32 && !strncmp (want_sn, "D27600012401", 12)) + { + /* This is an OpenPGP card - reformat */ + if (!strncmp (want_sn+16, "0006", 4)) + { + /* This is a Yubikey. Print the s/n as it would be printed + * on Yubikey 5. Example: D2760001240100000006120808620000 + * mmmm^^^^^^^^ */ + unsigned long sn; + + sn = atoi_4 (want_sn+20) * 10000; + sn += atoi_4 (want_sn+24); + snprintf (want_sn, 32, "%lu %03lu %03lu", + (sn/1000000ul), (sn/1000ul % 1000ul), (sn % 1000ul)); + } + else /* Default is the Zeitcontrol card print format. */ + { + memmove (want_sn, want_sn+16, 4); + want_sn[4] = ' '; + memmove (want_sn+5, want_sn+20, 8); + want_sn[13] = 0; + } + } + else if (len == 20 && want_sn[19] == '0') + { + /* We assume that a 20 byte serial number is a standard one + * which has the property to have a zero in the last nibble (Due + * to BCD representation). We don't display this '0' because it + * may confuse the user. */ + want_sn[19] = 0; + } + + for (;;) + { + /* Scan device(s), and check if key for GRIP is available. */ + err = agent_card_serialno (ctrl, &serialno, NULL); + if (!err) + { + struct card_key_info_s *keyinfo; + + xfree (serialno); + err = agent_card_keyinfo (ctrl, hexgrip, 0, &keyinfo); + if (!err) + { + /* Key for GRIP found, use it directly. */ + agent_card_free_keyinfo (keyinfo); + xfree (want_sn); + return 0; + } + } + + if (!want_sn) + ; /* No shadow info so we can't ask; ERR is already set. */ + else if (asprintf (&desc, + "%s:%%0A%%0A" + " %s", + L_("Please insert the card with serial number"), + want_sn) < 0) + { + err = out_of_core (); + } + else + { + err = agent_get_confirmation (ctrl, desc, NULL, NULL, 0); + if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK && + gpg_err_code (err) == GPG_ERR_NO_PIN_ENTRY) + err = gpg_error (GPG_ERR_CARD_NOT_PRESENT); + + xfree (desc); + } + + if (err) + { + xfree (want_sn); + return err; + } + } +} + + /* Return the secret key as an S-Exp in RESULT after locating it using the GRIP. Caller should set GRIP=NULL, when a key in a file is intended to be used for cryptographic operation. In this case, @@ -1143,24 +1249,36 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, if (shadow_info) { const unsigned char *s; + unsigned char *shadow_type; size_t n; - err = agent_get_shadow_info (buf, &s); + err = agent_get_shadow_info_type (buf, &s, &shadow_type); if (!err) { n = gcry_sexp_canon_len (s, 0, NULL,NULL); log_assert (n); *shadow_info = xtrymalloc (n); if (!*shadow_info) - err = out_of_core (); + { + err = out_of_core (); + goto shadow_error; + } else { memcpy (*shadow_info, s, n); - err = 0; + /* + * When it's a key on card (not on tpm2), maks sure + * it's available. + */ + if (strcmp (shadow_type, "t1-v1") == 0 && !grip) + err = prompt_for_card (ctrl, *shadow_info, ctrl->keygrip); } } - if (err) + else + shadow_error: log_error ("get_shadow_info failed: %s\n", gpg_strerror (err)); + + xfree (shadow_type); } else err = gpg_error (GPG_ERR_UNUSABLE_SECKEY); diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c index ba3d90469..82818f863 100644 --- a/agent/pkdecrypt.c +++ b/agent/pkdecrypt.c @@ -89,11 +89,11 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text, } if (agent_is_tpm2_key (s_skey)) - err = divert_tpm2_pkdecrypt (ctrl, desc_text, ciphertext, shadow_info, + err = divert_tpm2_pkdecrypt (ctrl, ciphertext, shadow_info, &buf, &len, r_padding); else - err = divert_pkdecrypt (ctrl, desc_text, ctrl->keygrip, ciphertext, - shadow_info, &buf, &len, r_padding); + err = divert_pkdecrypt (ctrl, ctrl->keygrip, ciphertext, + &buf, &len, r_padding); if (err) { log_error ("smartcard decryption failed: %s\n", gpg_strerror (err)); diff --git a/agent/pksign.c b/agent/pksign.c index a4aff041b..dfed0e398 100644 --- a/agent/pksign.c +++ b/agent/pksign.c @@ -392,23 +392,17 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce, } { - char *desc2 = NULL; - - if (desc_text) - agent_modify_description (desc_text, NULL, s_pkey, &desc2); - if (agent_is_tpm2_key (s_skey)) - err = divert_tpm2_pksign (ctrl, desc2? desc2 : desc_text, + err = divert_tpm2_pksign (ctrl, data, datalen, ctrl->digest.algo, shadow_info, &buf, &len); else - err = divert_pksign (ctrl, desc2? desc2 : desc_text, + err = divert_pksign (ctrl, ctrl->keygrip, data, datalen, ctrl->digest.algo, - shadow_info, &buf, &len); - xfree (desc2); + &buf, &len); } if (err) {