diff --git a/agent/ChangeLog b/agent/ChangeLog index 0c7930684..63cc94a84 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,22 @@ +2002-02-28 Werner Koch + + * pksign.c (agent_pksign): Detect whether a Smartcard is to be + used and divert the operation in this case. + * pkdecrypt.c (agent_pkdecrypt): Likewise + * findkey.c (agent_key_from_file): Add optional arg shadow_info + and have it return information about a shadowed key. + * protect.c (agent_get_shadow_info): New. + * divert-scd.c: New. + +2002-02-27 Werner Koch + + * protect.c (agent_shadow_key): New. + + * command.c (cmd_learn): New command LEARN. + * gpg-agent.c: New option --scdaemon-program. + * call-scd.c (start_scd): New. Based on query.c + * query.c: Add 2 more arguments to all uses of assuan_transact. + 2002-02-18 Werner Koch * findkey.c (unprotect): Show an error message for a bad passphrase. diff --git a/agent/Makefile.am b/agent/Makefile.am index eb5fa7d9d..d2b01b794 100644 --- a/agent/Makefile.am +++ b/agent/Makefile.am @@ -35,7 +35,9 @@ gpg_agent_SOURCES = \ pkdecrypt.c \ genkey.c \ protect.c \ - trustlist.c + trustlist.c \ + divert-scd.c \ + call-scd.c gpg_agent_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a \ ../common/libcommon.a $(LIBGCRYPT_LIBS) diff --git a/agent/agent.h b/agent/agent.h index a4cf8629d..875e69bf0 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -36,6 +36,7 @@ struct { int batch; /* batch mode */ const char *homedir; /* configuration directory name */ const char *pinentry_program; + const char *scdaemon_program; int no_grab; /* don't let the pinentry grab the keyboard */ unsigned long def_cache_ttl; @@ -101,7 +102,8 @@ const char *trans (const char *text); void start_command_handler (int); /*-- findkey.c --*/ -GCRY_SEXP agent_key_from_file (const unsigned char *grip); +GCRY_SEXP agent_key_from_file (const unsigned char *grip, + unsigned char **shadow_info); int agent_key_available (const unsigned char *grip); /*-- query.c --*/ @@ -135,6 +137,11 @@ int agent_protect (const unsigned char *plainkey, const char *passphrase, int agent_unprotect (const unsigned char *protectedkey, const char *passphrase, unsigned char **result, size_t *resultlen); int agent_private_key_type (const unsigned char *privatekey); +int agent_shadow_key (const unsigned char *pubkey, + const unsigned char *shadow_info, + unsigned char **result); +int agent_get_shadow_info (const unsigned char *shadowkey, + unsigned char const **shadow_info); /*-- trustlist.c --*/ @@ -143,4 +150,14 @@ int agent_listtrusted (void *assuan_context); int agent_marktrusted (const char *name, const char *fpr, int flag); +/*-- divert-scd.c --*/ +int divert_pksign (GCRY_SEXP *s_sig, GCRY_SEXP s_hash, + const char *shadow_info); +int divert_pkdecrypt (GCRY_SEXP *s_plain, GCRY_SEXP s_cipher, + const char *shadow_info); + +/*-- call-scd.c --*/ +int agent_learn_card (void); + + #endif /*AGENT_H*/ diff --git a/agent/command.c b/agent/command.c index 0a329627f..4e448f5a1 100644 --- a/agent/command.c +++ b/agent/command.c @@ -462,6 +462,22 @@ cmd_clear_passphrase (ASSUAN_CONTEXT ctx, char *line) return 0; } + +/* LEARN + + Learn something about the currently inserted smartcard + */ +static int +cmd_learn (ASSUAN_CONTEXT ctx, char *line) +{ + int rc; + + rc = agent_learn_card (); + if (rc) + log_error ("agent_learn_card failed: %s\n", gnupg_strerror (rc)); + return map_to_assuan_status (rc); +} + /* Tell the assuan library about our commands */ @@ -485,6 +501,7 @@ register_commands (ASSUAN_CONTEXT ctx) { "CLEAR_PASSPHRASE",0, cmd_clear_passphrase }, { "LISTTRUSTED", 0, cmd_listtrusted }, { "MARKTRUSTED", 0, cmd_marktrusted }, + { "LEARN", 0, cmd_learn }, { "", ASSUAN_CMD_INPUT, NULL }, { "", ASSUAN_CMD_OUTPUT, NULL }, { NULL } diff --git a/agent/findkey.c b/agent/findkey.c index 67e283442..14ad762d9 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -95,9 +95,12 @@ unprotect (unsigned char **keybuf, const unsigned char *grip) /* Return the secret key as an S-Exp after locating it using the grip. - Returns NULL if key is not available. */ + Returns NULL if key is not available or the operation should be + diverted to a token. In the latter case shadow_info will point to + an allocated S-Expression with the shadow_info part from the + file. */ GCRY_SEXP -agent_key_from_file (const unsigned char *grip) +agent_key_from_file (const unsigned char *grip, unsigned char **shadow_info) { int i, rc; char *fname; @@ -108,6 +111,9 @@ agent_key_from_file (const unsigned char *grip) GCRY_SEXP s_skey; char hexgrip[40+4+1]; + if (shadow_info) + *shadow_info = NULL; + for (i=0; i < 20; i++) sprintf (hexgrip+2*i, "%02X", grip[i]); strcpy (hexgrip+40, ".key"); @@ -173,8 +179,30 @@ agent_key_from_file (const unsigned char *grip) gnupg_strerror (rc)); break; case PRIVATE_KEY_SHADOWED: - log_error ("shadowed private keys are not yet supported\n"); - rc = GNUPG_Not_Implemented; + if (shadow_info) + { + const unsigned char *s; + size_t n; + + rc = agent_get_shadow_info (buf, &s); + if (!rc) + { + n = gcry_sexp_canon_len (s, 0, NULL,NULL); + assert (n); + *shadow_info = xtrymalloc (n); + if (!*shadow_info) + rc = GNUPG_Out_Of_Core; + else + { + memcpy (*shadow_info, s, n); + rc = 0; + } + } + if (rc) + log_error ("get_shadow_info failed: %s\n", gnupg_strerror (rc)); + } + rc = -1; /* ugly interface: we return an error but keep a value + in shadow_info. */ break; default: log_error ("invalid private key format\n"); diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index 5e014bbc1..ca49a8463 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -69,6 +69,7 @@ enum cmd_and_opt_values oBatch, oPinentryProgram, + oScdaemonProgram, oDefCacheTTL, aTest }; @@ -92,7 +93,8 @@ static ARGPARSE_OPTS opts[] = { { oNoGrab, "no-grab" ,0, N_("do not grab keyboard and mouse")}, { oLogFile, "log-file" ,2, N_("use a log file for the server")}, - { oPinentryProgram, "pinentry-program", 2 , "path of PIN Entry program" }, + { oPinentryProgram, "pinentry-program", 2 , "path to PIN Entry program" }, + { oScdaemonProgram, "scdaemon-program", 2 , "path to SCdaemon program" }, { oDefCacheTTL, "default-cache-ttl", 4, "|N|expire cached PINs after N seconds"}, @@ -372,6 +374,7 @@ main (int argc, char **argv ) case oServer: pipe_server = 1; break; case oPinentryProgram: opt.pinentry_program = pargs.r.ret_str; break; + case oScdaemonProgram: opt.scdaemon_program = pargs.r.ret_str; break; case oDefCacheTTL: opt.def_cache_ttl = pargs.r.ret_ulong; break; default : pargs.err = configfp? 1:2; break; diff --git a/agent/keyformat.txt b/agent/keyformat.txt index ab2ad65fd..bfb4ee4d4 100644 --- a/agent/keyformat.txt +++ b/agent/keyformat.txt @@ -4,7 +4,8 @@ keyformat.txt (wk 2001-12-18) Some notes on the format of the secret keys used with gpg-agent. - +Location of keys +================ The secret keys[1] are stored on a per file basis in a directory below the ~/.gnupg home directory. This directory is named @@ -13,9 +14,12 @@ the ~/.gnupg home directory. This directory is named and should have permissions 700. The secret keys are stored in files with a name matching the -hexadecimal representation of the keygrip[2]. The content of the file -is an S-Expression like the ones used with Libgcrypt. Here is an -example of an unprotected file: +hexadecimal representation of the keygrip[2]. + +Unprotected Private Key Format +============================== +The content of the file is an S-Expression like the ones used with +Libgcrypt. Here is an example of an unprotected file: (private-key (rsa @@ -47,8 +51,9 @@ keys is in canonical representation[3]: ) - -This describes an unprotected key; a protected key is like this: +Protected Private Key Format +============================== +A protected key is like this: (protected-private-key (rsa @@ -116,12 +121,35 @@ the stored one - If they don't match the integrity of the key is not given. +Shadowed Private Key Format +============================ +To keep track of keys stored on IC cards we use a third format for +private kyes which are called shadow keys as they are only a reference +to keys stored on a token: + +(shadowed-private-key + (rsa + (n #00e0ce9..[some bytes not shown]..51#) + (e #010001#) + (shadowed protocol (info)) + ) + (uri http://foo.bar x-foo:whatever_you_want) +) + +The currently used protocol is "ti-v1" (token info version 1). The +second list with the information has this layout: + +(card_serial_number id_string_of_key) + +More items may be added to the list. + + Notes: - +====== [1] I usually use the terms private and secret key exchangeable but prefer the term secret key because it can be visually be better distinguished from the term public key. diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c index 78f70ad52..33663a9f7 100644 --- a/agent/pkdecrypt.c +++ b/agent/pkdecrypt.c @@ -39,6 +39,7 @@ agent_pkdecrypt (CTRL ctrl, const char *ciphertext, size_t ciphertextlen, FILE *outfp) { GCRY_SEXP s_skey = NULL, s_cipher = NULL, s_plain = NULL; + unsigned char *shadow_info = NULL; int rc; char *buf = NULL; size_t len; @@ -63,27 +64,38 @@ agent_pkdecrypt (CTRL ctrl, const char *ciphertext, size_t ciphertextlen, log_printhex ("keygrip:", ctrl->keygrip, 20); log_printhex ("cipher: ", ciphertext, ciphertextlen); } - s_skey = agent_key_from_file (ctrl->keygrip); - if (!s_skey) + s_skey = agent_key_from_file (ctrl->keygrip, &shadow_info); + if (!s_skey && !shadow_info) { log_error ("failed to read the secret key\n"); rc = seterr (No_Secret_Key); goto leave; } - - if (DBG_CRYPTO) - { - log_debug ("skey: "); - gcry_sexp_dump (s_skey); + if (!s_skey) + { /* divert operation to the smartcard */ + rc = divert_pkdecrypt (&s_plain, s_cipher, shadow_info); + if (rc) + { + log_error ("smartcard decryption failed: %s\n", gnupg_strerror (rc)); + goto leave; + } } + else + { /* no smartcard, but a private key */ + if (DBG_CRYPTO) + { + log_debug ("skey: "); + gcry_sexp_dump (s_skey); + } - rc = gcry_pk_decrypt (&s_plain, s_cipher, s_skey); - if (rc) - { - log_error ("decryption failed: %s\n", gcry_strerror (rc)); - rc = map_gcry_err (rc); - goto leave; - } + rc = gcry_pk_decrypt (&s_plain, s_cipher, s_skey); + if (rc) + { + log_error ("decryption failed: %s\n", gcry_strerror (rc)); + rc = map_gcry_err (rc); + goto leave; + } + } if (DBG_CRYPTO) { @@ -106,6 +118,7 @@ agent_pkdecrypt (CTRL ctrl, const char *ciphertext, size_t ciphertextlen, gcry_sexp_release (s_plain); gcry_sexp_release (s_cipher); xfree (buf); + xfree (shadow_info); return rc; } diff --git a/agent/pksign.c b/agent/pksign.c index 9d1ad4f67..6ec37cd14 100644 --- a/agent/pksign.c +++ b/agent/pksign.c @@ -90,6 +90,7 @@ agent_pksign (CTRL ctrl, FILE *outfp) { GCRY_SEXP s_skey = NULL, s_hash = NULL, s_sig = NULL; GCRY_MPI frame = NULL; + unsigned char *shadow_info = NULL; int rc; char *buf = NULL; size_t len; @@ -97,39 +98,50 @@ agent_pksign (CTRL ctrl, FILE *outfp) if (!ctrl->have_keygrip) return seterr (No_Secret_Key); - s_skey = agent_key_from_file (ctrl->keygrip); - if (!s_skey) + s_skey = agent_key_from_file (ctrl->keygrip, &shadow_info); + if (!s_skey && !shadow_info) { log_error ("failed to read the secret key\n"); rc = seterr (No_Secret_Key); goto leave; } - /* put the hash into a sexp */ + /* put the hash into a sexp FIXME: this belongs into libgcrypt/divert-scd.c*/ rc = do_encode_md (ctrl->digest.value, ctrl->digest.valuelen, ctrl->digest.algo, gcry_pk_get_nbits (s_skey), &frame); if (rc) - goto leave; + goto leave; if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) ) BUG (); - if (DBG_CRYPTO) - { - log_debug ("skey: "); - gcry_sexp_dump (s_skey); + if (!s_skey) + { /* divert operation to the smartcard */ + rc = divert_pksign (&s_sig, s_hash, shadow_info); + if (rc) + { + log_error ("smartcard signing failed: %s\n", gnupg_strerror (rc)); + goto leave; + } } + else + { /* no smartcard, but a private key */ + if (DBG_CRYPTO) + { + log_debug ("skey: "); + gcry_sexp_dump (s_skey); + } - - /* sign */ - rc = gcry_pk_sign (&s_sig, s_hash, s_skey); - if (rc) - { - log_error ("signing failed: %s\n", gcry_strerror (rc)); - rc = map_gcry_err (rc); - goto leave; + /* sign */ + rc = gcry_pk_sign (&s_sig, s_hash, s_skey); + if (rc) + { + log_error ("signing failed: %s\n", gcry_strerror (rc)); + rc = map_gcry_err (rc); + goto leave; + } } if (DBG_CRYPTO) @@ -138,7 +150,6 @@ agent_pksign (CTRL ctrl, FILE *outfp) gcry_sexp_dump (s_sig); } - len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, NULL, 0); assert (len); buf = xmalloc (len); @@ -156,6 +167,7 @@ agent_pksign (CTRL ctrl, FILE *outfp) gcry_sexp_release (s_sig); gcry_mpi_release (frame); xfree (buf); + xfree (shadow_info); return rc; } diff --git a/agent/protect-tool.c b/agent/protect-tool.c index df58290ed..e10662880 100644 --- a/agent/protect-tool.c +++ b/agent/protect-tool.c @@ -49,6 +49,8 @@ enum cmd_and_opt_values oUnprotect = 'u', oNoVerbose = 500, + oShadow, + oShowShadowInfo, aTest }; @@ -65,6 +67,8 @@ static ARGPARSE_OPTS opts[] = { { oPassphrase, "passphrase", 2, "|STRING| Use passphrase STRING" }, { oProtect, "protect", 256, "protect a private key"}, { oUnprotect, "unprotect", 256, "unprotect a private key"}, + { oShadow, "shadow", 256, "create a shadow entry for a priblic key"}, + { oShowShadowInfo, "show-shadow-info", 256, "return the shadow info"}, {0} }; @@ -125,8 +129,7 @@ my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr) case GCRY_LOG_FATAL:level = JNLIB_LOG_FATAL; break; case GCRY_LOG_BUG: level = JNLIB_LOG_BUG; break; case GCRY_LOG_DEBUG:level = JNLIB_LOG_DEBUG; break; - default: level = JNLIB_LOG_ERROR; break; - } + default: level = JNLIB_LOG_ERROR; break; } log_logv (level, fmt, arg_ptr); } @@ -291,6 +294,79 @@ read_and_unprotect (const char *fname) } + +static void +read_and_shadow (const char *fname) +{ + int rc; + unsigned char *key; + unsigned char *result; + size_t resultlen; + + key = read_key (fname); + if (!key) + return; + + rc = agent_shadow_key (key, "(8:313233342:43)", &result); + xfree (key); + if (rc) + { + log_error ("shadowing the key failed: %s\n", gnupg_strerror (rc)); + return; + } + resultlen = gcry_sexp_canon_len (result, 0, NULL,NULL); + assert (resultlen); + + if (opt_armor) + { + char *p = make_advanced (result, resultlen); + xfree (result); + if (!p) + return; + result = p; + resultlen = strlen (p); + } + + fwrite (result, resultlen, 1, stdout); + xfree (result); +} + +static void +show_shadow_info (const char *fname) +{ + int rc; + unsigned char *key; + const unsigned char *info; + size_t infolen; + + key = read_key (fname); + if (!key) + return; + + rc = agent_get_shadow_info (key, &info); + xfree (key); + if (rc) + { + log_error ("get_shadow_info failed: %s\n", gnupg_strerror (rc)); + return; + } + infolen = gcry_sexp_canon_len (info, 0, NULL,NULL); + assert (infolen); + + if (opt_armor) + { + char *p = make_advanced (info, infolen); + if (!p) + return; + fwrite (p, strlen (p), 1, stdout); + xfree (p); + } + else + fwrite (info, infolen, 1, stdout); +} + + + int main (int argc, char **argv ) @@ -325,6 +401,8 @@ main (int argc, char **argv ) case oProtect: cmd = oProtect; break; case oUnprotect: cmd = oUnprotect; break; + case oShadow: cmd = oShadow; break; + case oShowShadowInfo: cmd = oShowShadowInfo; break; case oPassphrase: passphrase = pargs.r.ret_str; break; @@ -341,6 +419,10 @@ main (int argc, char **argv ) read_and_protect (*argv); else if (cmd == oUnprotect) read_and_unprotect (*argv); + else if (cmd == oShadow) + read_and_shadow (*argv); + else if (cmd == oShowShadowInfo) + show_shadow_info (*argv); else log_info ("no action requested\n"); diff --git a/agent/protect.c b/agent/protect.c index 115a94563..ea8e30496 100644 --- a/agent/protect.c +++ b/agent/protect.c @@ -780,7 +780,7 @@ agent_unprotect (const unsigned char *protectedkey, const char *passphrase, PRIVATE_KEY_UNKNOWN if we can't figure out the type (this is the value 0), PRIVATE_KEY_CLEAR for an unprotected private key. PRIVATE_KEY_PROTECTED for an protected private key or - PRIVATE_KEY_SHADOWED for a sub key where the secret parts are store + PRIVATE_KEY_SHADOWED for a sub key where the secret parts are stored elsewhere. */ int agent_private_key_type (const unsigned char *privatekey) @@ -886,3 +886,154 @@ hash_passphrase (const char *passphrase, int hashalgo, } + +/* Create a shadow key from a public key. We use the shadow protocol + "ti-v1" and insert the S-expressionn SHADOW_INFO. The resulting + S-expression is returned in an allocated buffer RESULT will point + to. The input parameters are expected to be valid canonilized + S-expressions */ +int +agent_shadow_key (const unsigned char *pubkey, + const unsigned char *shadow_info, + unsigned char **result) +{ + const unsigned char *s; + const unsigned char *point; + size_t n; + int depth = 0; + unsigned char *p; + size_t pubkey_len = gcry_sexp_canon_len (pubkey, 0, NULL,NULL); + size_t shadow_info_len = gcry_sexp_canon_len (shadow_info, 0, NULL,NULL); + + if (!pubkey_len || !shadow_info_len) + return GNUPG_Invalid_Value; + s = pubkey; + if (*s != '(') + return GNUPG_Invalid_Sexp; + depth++; + s++; + n = snext (&s); + if (!n) + return GNUPG_Invalid_Sexp; + if (!smatch (&s, n, "public-key")) + return GNUPG_Unknown_Sexp; + if (*s != '(') + return GNUPG_Unknown_Sexp; + depth++; + s++; + n = snext (&s); + if (!n) + return GNUPG_Invalid_Sexp; + s += n; /* skip over the algorithm name */ + + while (*s != ')') + { + if (*s != '(') + return GNUPG_Invalid_Sexp; + depth++; + s++; + n = snext (&s); + if (!n) + return GNUPG_Invalid_Sexp; + s += n; + n = snext (&s); + if (!n) + return GNUPG_Invalid_Sexp; + s +=n; /* skip value */ + if (*s != ')') + return GNUPG_Invalid_Sexp; + depth--; + s++; + } + point = s; /* insert right before the point */ + depth--; + s++; + assert (depth == 1); + + /* calculate required length by taking in account: the "shadowed-" + prefix, the "shadowed", "t1-v1" as well as some parenthesis */ + n = 12 + pubkey_len + 1 + 3+8 + 2+5 + shadow_info_len + 1; + *result = p = xtrymalloc (n); + if (!p) + return GNUPG_Out_Of_Core; + p = stpcpy (p, "(20:shadowed-private-key"); + /* (10:public-key ...)*/ + memcpy (p, pubkey+14, point - (pubkey+14)); + p += point - (pubkey+14); + p = stpcpy (p, "(8:shadowed5:t1-v1"); + memcpy (p, shadow_info, shadow_info_len); + p += shadow_info_len; + *p++ = ')'; + memcpy (p, point, pubkey_len - (point - pubkey)); + p += pubkey_len - (point - pubkey); + + return 0; +} + +/* Parse a canonical encoded shadowed key and return a pointer to the + inner list with the shadow_info */ +int +agent_get_shadow_info (const unsigned char *shadowkey, + unsigned char const **shadow_info) +{ + const unsigned char *s; + size_t n; + int depth = 0; + + s = shadowkey; + if (*s != '(') + return GNUPG_Invalid_Sexp; + depth++; + s++; + n = snext (&s); + if (!n) + return GNUPG_Invalid_Sexp; + if (!smatch (&s, n, "shadowed-private-key")) + return GNUPG_Unknown_Sexp; + if (*s != '(') + return GNUPG_Unknown_Sexp; + depth++; + s++; + n = snext (&s); + if (!n) + return GNUPG_Invalid_Sexp; + s += n; /* skip over the algorithm name */ + + for (;;) + { + if (*s == ')') + return GNUPG_Unknown_Sexp; + if (*s != '(') + return GNUPG_Invalid_Sexp; + depth++; + s++; + n = snext (&s); + if (!n) + return GNUPG_Invalid_Sexp; + if (smatch (&s, n, "shadowed")) + break; + s += n; + n = snext (&s); + if (!n) + return GNUPG_Invalid_Sexp; + s +=n; /* skip value */ + if (*s != ')') + return GNUPG_Invalid_Sexp; + depth--; + s++; + } + /* found the shadowed list, s points to the protocol */ + n = snext (&s); + if (!n) + return GNUPG_Invalid_Sexp; + if (smatch (&s, n, "t1-v1")) + { + if (*s != '(') + return GNUPG_Invalid_Sexp; + *shadow_info = s; + } + else + return GNUPG_Unsupported_Protocol; + return 0; +} + diff --git a/agent/query.c b/agent/query.c index 1abfefcd9..795e214e3 100644 --- a/agent/query.c +++ b/agent/query.c @@ -97,7 +97,7 @@ start_pinentry (void) rc = assuan_transact (entry_ctx, opt.no_grab? "OPTION no-grab":"OPTION grab", - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return map_assuan_err (rc); @@ -160,14 +160,14 @@ agent_askpin (const char *desc_text, const char *start_err_text, snprintf (line, DIM(line)-1, "SETDESC %s", desc_text); line[DIM(line)-1] = 0; - rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL); + rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return map_assuan_err (rc); rc = assuan_transact (entry_ctx, pininfo->min_digits? "SETPROMPT PIN:" : "SETPROMPT Passphrase:", - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return map_assuan_err (rc); @@ -189,13 +189,13 @@ agent_askpin (const char *desc_text, const char *start_err_text, snprintf (line, DIM(line)-1, "SETERROR %s (try %d of %d)", errtext, pininfo->failed_tries+1, pininfo->max_tries); line[DIM(line)-1] = 0; - rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL); + rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return map_assuan_err (rc); errtext = NULL; } - rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL); + rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL, NULL, NULL); if (rc == ASSUAN_Too_Much_Data) errtext = pininfo->min_digits? trans ("PIN too long") : trans ("Passphrase too long"); @@ -248,13 +248,13 @@ agent_get_passphrase (char **retpass, const char *desc, const char *prompt, else snprintf (line, DIM(line)-1, "RESET"); line[DIM(line)-1] = 0; - rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL); + rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return map_assuan_err (rc); snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt? prompt : "Passphrase"); line[DIM(line)-1] = 0; - rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL); + rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return map_assuan_err (rc); @@ -262,7 +262,7 @@ agent_get_passphrase (char **retpass, const char *desc, const char *prompt, { snprintf (line, DIM(line)-1, "SETERROR %s", errtext); line[DIM(line)-1] = 0; - rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL); + rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return map_assuan_err (rc); } @@ -274,7 +274,7 @@ agent_get_passphrase (char **retpass, const char *desc, const char *prompt, return seterr (Out_Of_Core); assuan_begin_confidential (entry_ctx); - rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL); + rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL, NULL, NULL); if (rc) { xfree (parm.buffer); @@ -317,7 +317,7 @@ agent_get_confirmation (const char *desc, const char *prompt) else snprintf (line, DIM(line)-1, "RESET"); line[DIM(line)-1] = 0; - rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL); + rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return map_assuan_err (rc); @@ -325,12 +325,12 @@ agent_get_confirmation (const char *desc, const char *prompt) { snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt); line[DIM(line)-1] = 0; - rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL); + rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return map_assuan_err (rc); } - rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL); + rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL); return map_assuan_err (rc); } diff --git a/common/errors.h b/common/errors.h index 42842afe7..a8389f88d 100644 --- a/common/errors.h +++ b/common/errors.h @@ -94,6 +94,11 @@ enum { GNUPG_Not_Confirmed = 65, GNUPG_Configuration_Error = 66, GNUPG_No_Policy_Match = 67, + GNUPG_Invalid_Index = 68, + GNUPG_Invalid_Id = 69, + GNUPG_No_Scdaemon = 70, + GNUPG_Scdaemon_Error = 71, + GNUPG_Unsupported_Protocol = 72, }; /* Status codes - fixme: should go into another file */ diff --git a/common/maperror.c b/common/maperror.c index 91c97f936..30bdf07a5 100644 --- a/common/maperror.c +++ b/common/maperror.c @@ -44,6 +44,7 @@ map_ksba_err (int err) break; case KSBA_Unsupported_Algorithm: err = GNUPG_Unsupported_Algorithm; break; + case KSBA_Invalid_Index: err = GNUPG_Invalid_Index; break; default: err = seterr (General_Error); @@ -136,6 +137,7 @@ map_assuan_err (int err) break; case ASSUAN_Canceled: err = GNUPG_Canceled; break; + case ASSUAN_Invalid_Index: err = GNUPG_Invalid_Index; break; case ASSUAN_Not_Implemented: err = GNUPG_Not_Implemented; break; case ASSUAN_Server_Fault: err = GNUPG_Assuan_Server_Fault; break; @@ -153,6 +155,7 @@ map_assuan_err (int err) case ASSUAN_No_PKCS15_App: err = GNUPG_No_PKCS15_App; break; case ASSUAN_Card_Not_Present: err= GNUPG_Card_Not_Present; break; case ASSUAN_Not_Confirmed: err = GNUPG_Not_Confirmed; break; + case ASSUAN_Invalid_Id: err = GNUPG_Invalid_Id; break; default: err = err < 100? GNUPG_Assuan_Server_Fault : GNUPG_Assuan_Error; @@ -182,6 +185,7 @@ map_to_assuan_status (int rc) case GNUPG_Invalid_Name: rc = ASSUAN_Invalid_Name; break; case GNUPG_Not_Trusted: rc = ASSUAN_Not_Trusted; break; case GNUPG_Canceled: rc = ASSUAN_Canceled; break; + case GNUPG_Invalid_Index: rc = ASSUAN_Invalid_Index; break; case GNUPG_Card_Error: case GNUPG_Card_Reset: @@ -194,7 +198,7 @@ map_to_assuan_status (int rc) case GNUPG_Invalid_Card: rc = ASSUAN_Invalid_Card; break; case GNUPG_No_PKCS15_App: rc = ASSUAN_No_PKCS15_App; break; case GNUPG_Not_Confirmed: rc = ASSUAN_Not_Confirmed; break; - + case GNUPG_Invalid_Id: rc = ASSUAN_Invalid_Id; break; case GNUPG_Bad_PIN: case GNUPG_Bad_Passphrase: diff --git a/scd/Makefile.am b/scd/Makefile.am index dca4f3bcb..5379d519a 100644 --- a/scd/Makefile.am +++ b/scd/Makefile.am @@ -20,7 +20,8 @@ bin_PROGRAMS = scdaemon -AM_CPPFLAGS = -I$(top_srcdir)/common $(LIBOPENSC_CFLAGS) $(LIBGCRYPT_CFLAGS) +AM_CPPFLAGS = -I$(top_srcdir)/common $(LIBOPENSC_CFLAGS) $(LIBGCRYPT_CFLAGS) \ + $(LIBKSBA_CFLAGS) LDFLAGS = @LDFLAGS@ scdaemon_SOURCES = \ @@ -29,7 +30,8 @@ scdaemon_SOURCES = \ scdaemon_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a \ - ../common/libcommon.a $(LIBOPENSC_LIBS) $(LIBGCRYPT_LIBS) + ../common/libcommon.a \ + $(LIBOPENSC_LIBS) $(LIBGCRYPT_LIBS) $(LIBKSBA_LIBS) diff --git a/scd/card.c b/scd/card.c index 3702ae348..dbfbe5333 100644 --- a/scd/card.c +++ b/scd/card.c @@ -26,6 +26,7 @@ #include #include +#include #include "scdaemon.h" @@ -114,13 +115,13 @@ card_open (CARD *rcard) } card->ctx->error_file = log_get_stream (); card->ctx->debug_file = log_get_stream (); - if (sc_detect_card (card->ctx, card->reader) != 1) + if (sc_detect_card_presence (card->ctx->reader[card->reader], 0) != 1) { rc = GNUPG_Card_Not_Present; goto leave; } - rc = sc_connect_card (card->ctx, card->reader, &card->scard); + rc = sc_connect_card (card->ctx->reader[card->reader], 0, &card->scard); if (rc) { log_error ("failed to connect card in reader %d: %s\n", @@ -175,7 +176,7 @@ card_close (CARD card) if (card->scard) { sc_unlock (card->scard); - sc_disconnect_card (card->scard); + sc_disconnect_card (card->scard, 0); card->scard = NULL; } if (card->ctx) @@ -219,3 +220,204 @@ card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp) return GNUPG_Out_Of_Core; return 0; } + + + +/* Get the keygrip from CERT, return 0 on success */ +static int +get_keygrip (KsbaCert cert, unsigned char *array) +{ + GCRY_SEXP s_pkey; + int rc; + KsbaSexp p; + size_t n; + + p = ksba_cert_get_public_key (cert); + if (!p) + return -1; /* oops */ + n = gcry_sexp_canon_len (p, 0, NULL, NULL); + if (!n) + return -1; /* libksba did not return a proper S-expression */ + rc = gcry_sexp_sscan ( &s_pkey, NULL, p, n); + xfree (p); + if (rc) + return -1; /* can't parse that S-expression */ + array = gcry_pk_get_keygrip (s_pkey, array); + gcry_sexp_release (s_pkey); + if (!array) + return -1; /* failed to calculate the keygrip */ + return 0; +} + + + +/* Enumerate all keypairs on the card and return the Keygrip as well + as the internal identification of the key. KEYGRIP must be a + caller provided buffer with a size of 20 bytes which will receive + the KEYGRIP of the keypair. If KEYID is not NULL, it returns the + ID field of the key in allocated memory, NKEYID will then receive + the length of it. The function returns -1 when all keys have been + enumerated. Note that the error GNUPG_Missing_Certificate may be + returned if there is just the private key but no public key (ie.e a + certificate) available. Applications might want to continue + enumerating after this error.*/ +int +card_enum_keypairs (CARD card, int idx, + unsigned char *keygrip, + unsigned char **keyid, size_t *nkeyid) +{ + int rc; + KsbaError krc; + struct sc_pkcs15_prkey_info *pinfo; + struct sc_pkcs15_cert_info *certinfo; + struct sc_pkcs15_cert *certder; + KsbaCert cert; + + if (keyid) + *keyid = NULL; + if (nkeyid) + *nkeyid = 0; + + if (!card || !keygrip || !card->p15card) + return GNUPG_Invalid_Value; + if (idx < 0) + return GNUPG_Invalid_Index; + + rc = sc_pkcs15_enum_private_keys (card->p15card); + if (rc < 0) + { + log_error ("sc_pkcs15_enum_private_keys failed: %s\n", sc_strerror (rc)); + return GNUPG_Card_Error; + } + if ( idx >= card->p15card->prkey_count) + return -1; + pinfo = card->p15card->prkey_info + idx; + + /* now we need to read the certificate so that we can calculate the + keygrip */ + rc = sc_pkcs15_find_cert_by_id (card->p15card, &pinfo->id, &certinfo); + if (rc) + { + log_info ("certificate for private key %d not found: %s\n", + idx, sc_strerror (rc)); + /* but we should return the ID anyway */ + if (keyid) + { + *keyid = xtrymalloc (pinfo->id.len); + if (!*keyid) + return GNUPG_Out_Of_Core; + memcpy (*keyid, pinfo->id.value, pinfo->id.len); + } + if (nkeyid) + *nkeyid = pinfo->id.len; + return GNUPG_Missing_Certificate; + } + rc = sc_pkcs15_read_certificate (card->p15card, certinfo, &certder); + if (rc) + { + log_info ("failed to read certificate for private key %d: %s\n", + idx, sc_strerror (rc)); + return GNUPG_Card_Error; + } + + cert = ksba_cert_new (); + if (!cert) + { + sc_pkcs15_free_certificate (certder); + return GNUPG_Out_Of_Core; + } + krc = ksba_cert_init_from_mem (cert, certder->data, certder->data_len); + sc_pkcs15_free_certificate (certder); + if (krc) + { + log_error ("failed to parse the certificate for private key %d: %s\n", + idx, ksba_strerror (krc)); + ksba_cert_release (cert); + return GNUPG_Card_Error; + } + if (get_keygrip (cert, keygrip)) + { + log_error ("failed to calculate the keygrip of private key %d\n", idx); + ksba_cert_release (cert); + return GNUPG_Card_Error; + } + ksba_cert_release (cert); + + /* return the iD */ + if (keyid) + { + *keyid = xtrymalloc (pinfo->id.len); + if (!*keyid) + return GNUPG_Out_Of_Core; + memcpy (*keyid, pinfo->id.value, pinfo->id.len); + } + if (nkeyid) + *nkeyid = pinfo->id.len; + + return 0; +} + + + +/* Read the certificate identified by CERTIDSTR which is the + hexadecimal encoded ID of the certificate, prefixed with the string + "3F005015.". The certificate is return in DER encoded form in CERT + and NCERT. */ +int +card_read_cert (CARD card, const char *certidstr, + unsigned char **cert, size_t *ncert) +{ + struct sc_pkcs15_id certid; + struct sc_pkcs15_cert_info *certinfo; + struct sc_pkcs15_cert *certder; + const char *s; + int rc, n; + + if (!card || !certidstr || !card->p15card || !cert || !ncert) + return GNUPG_Invalid_Value; + + /* For now we only support the standard DF */ + if (strncmp (certidstr, "3F005015.", 9) ) + return GNUPG_Invalid_Id; + for (s=certidstr+9, n=0; hexdigitp (s); s++, n++) + ; + if (*s || (n&1)) + return GNUPG_Invalid_Id; /* invalid or odd number of digits */ + n /= 2; + if (!n || n > SC_PKCS15_MAX_ID_SIZE) + return GNUPG_Invalid_Id; /* empty or too large */ + for (s=certidstr+9, n=0; *s; s += 2, n++) + certid.value[n] = xtoi_2 (s); + certid.len = n; + + rc = sc_pkcs15_find_cert_by_id (card->p15card, &certid, &certinfo); + if (rc) + { + log_info ("certificate '%s' not found: %s\n", + certidstr, sc_strerror (rc)); + return -1; + } + rc = sc_pkcs15_read_certificate (card->p15card, certinfo, &certder); + if (rc) + { + log_info ("failed to read certificate '%s': %s\n", + certidstr, sc_strerror (rc)); + return GNUPG_Card_Error; + } + + *cert = xtrymalloc (certder->data_len); + if (!*cert) + { + sc_pkcs15_free_certificate (certder); + return GNUPG_Out_Of_Core; + } + memcpy (*cert, certder->data, certder->data_len); + *ncert = certder->data_len; + sc_pkcs15_free_certificate (certder); + return 0; +} + + + + + diff --git a/scd/command.c b/scd/command.c index 10b900628..b4eaa8a47 100644 --- a/scd/command.c +++ b/scd/command.c @@ -75,14 +75,20 @@ option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value) /* LEARN [--force] Learn all useful information of the currently inserted card. When - used without the force options, the command might to an INQUIRE + used without the force options, the command might do an INQUIRE like this: INQUIRE KNOWNCARDP The client should just send an "END" if the processing should go on or a "CANCEL" to force the function to terminate with a Cancel - error message. + error message. The response of this command is a list of status + lines formatted as this: + + S KEYPAIRINFO + + If there is no certificate yet stored on the card a single "X" is + returned as the keygrip. */ static int @@ -90,6 +96,7 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc = 0; + int idx; /* if this is the first command issued for a new card, open the card and and create a context */ @@ -104,40 +111,138 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line) the card using a serial number and inquiring the client with that. The client may choose to cancel the operation if he already knows about this card */ - if (!has_option (line, "--force")) + { + char *serial_and_stamp; + char *serial; + time_t stamp; + + rc = card_get_serial_and_stamp (ctrl->card_ctx, &serial, &stamp); + if (rc) + return map_to_assuan_status (rc); + rc = asprintf (&serial_and_stamp, "%s %lu", serial, (unsigned long)stamp); + xfree (serial); + if (rc < 0) + return ASSUAN_Out_Of_Core; + rc = 0; + assuan_write_status (ctx, "SERIALNO", serial_and_stamp); + + if (!has_option (line, "--force")) + { + char *command; + + rc = asprintf (&command, "KNOWNCARDP %s", serial_and_stamp); + if (rc < 0) + { + free (serial_and_stamp); + return ASSUAN_Out_Of_Core; + } + rc = 0; + rc = assuan_inquire (ctx, command, NULL, NULL, 0); + free (command); /* (must use standard free here) */ + if (rc) + { + if (rc != ASSUAN_Canceled) + log_error ("inquire KNOWNCARDP failed: %s\n", + assuan_strerror (rc)); + free (serial_and_stamp); + return rc; + } + /* not canceled, so we have to proceeed */ + } + free (serial_and_stamp); + } + + for (idx=0; !rc; idx++) { - char *serial; - time_t stamp; - char *command; + unsigned char keygrip[20]; + unsigned char *keyid; + size_t nkeyid; + int no_cert = 0; - rc = card_get_serial_and_stamp (ctrl->card_ctx, &serial, &stamp); - if (rc) - return map_to_assuan_status (rc); - - rc = asprintf (&command, "KNOWNCARDP %s %lu", - serial, (unsigned long)stamp); - xfree (serial); - if (rc < 0) - return ASSUAN_Out_Of_Core; - rc = 0; - rc = assuan_inquire (ctx, command, NULL, NULL, 0); - free (command); /* (must use standard free here) */ - if (rc) + rc = card_enum_keypairs (ctrl->card_ctx, idx, + keygrip, &keyid, &nkeyid); + if (rc == GNUPG_Missing_Certificate && keyid) { - if (rc != ASSUAN_Canceled) - log_error ("inquire KNOWNCARDP failed: %s\n", - assuan_strerror (rc)); - return rc; + /* this does happen with an incomplete personalized + card; i.e. during the time we have stored the key on the + card but not stored the certificate; probably becuase it + has not yet been received back from the CA. Note that we + must release KEYID in this case. */ + rc = 0; + no_cert = 1; } - /* not canceled, so we have to proceeed */ + if (!rc) + { + char *buf, *p; + + buf = p = xtrymalloc (40+1+9+2*nkeyid+1); + if (!buf) + rc = GNUPG_Out_Of_Core; + else + { + int i; + + if (no_cert) + *p++ = 'X'; + else + { + for (i=0; i < 20; i++, p += 2) + sprintf (p, "%02X", keygrip[i]); + } + *p++ = ' '; + /* fixme: we need to get the pkcs-15 DF from the card function */ + p = stpcpy (p, "3F005015."); + for (i=0; i < nkeyid; i++, p += 2) + sprintf (p, "%02X", keyid[i]); + *p = 0; + assuan_write_status (ctx, "KEYPAIRINFO", buf); + xfree (buf); + } + } + xfree (keyid); } + if (rc == -1) + rc = 0; + return map_to_assuan_status (rc); } + +/* READCERT + */ +static int +cmd_readcert (ASSUAN_CONTEXT ctx, char *line) +{ + CTRL ctrl = assuan_get_pointer (ctx); + int rc; + unsigned char *cert; + size_t ncert; + if (!ctrl->card_ctx) + { + rc = card_open (&ctrl->card_ctx); + if (rc) + return map_to_assuan_status (rc); + } + + rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert); + if (rc) + { + log_error ("card_read_cert failed: %s\n", gnupg_strerror (rc)); + } + if (!rc) + { + rc = assuan_send_data (ctx, cert, ncert); + xfree (cert); + if (rc) + return rc; + } + + return map_to_assuan_status (rc); +} /* Tell the assuan library about our commands */ @@ -150,6 +255,7 @@ register_commands (ASSUAN_CONTEXT ctx) int (*handler)(ASSUAN_CONTEXT, char *line); } table[] = { { "LEARN", 0, cmd_learn }, + { "READCERT", 0, cmd_readcert }, { "", ASSUAN_CMD_INPUT, NULL }, { "", ASSUAN_CMD_OUTPUT, NULL }, { NULL } diff --git a/scd/scdaemon.c b/scd/scdaemon.c index d217b0020..92bccec9e 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -34,6 +34,7 @@ #include #include +#include #include #define JNLIB_NEED_LOG_LOGV @@ -242,6 +243,7 @@ main (int argc, char **argv ) "1.1.5", gcry_check_version (NULL) ); } + ksba_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free); assuan_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free); gcry_set_log_handler (my_gcry_logger, NULL); gcry_control (GCRYCTL_USE_SECURE_RNDPOOL); diff --git a/scd/scdaemon.h b/scd/scdaemon.h index 7d43dc129..e77012416 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -77,6 +77,11 @@ void scd_command_handler (int); int card_open (CARD *rcard); void card_close (CARD card); int card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp); +int card_enum_keypairs (CARD card, int idx, + unsigned char *keygrip, + unsigned char **keyid, size_t *nkeyid); +int card_read_cert (CARD card, const char *certidstr, + unsigned char **cert, size_t *ncert); diff --git a/sm/ChangeLog b/sm/ChangeLog index 8388b3921..4bddd2487 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,8 @@ +2002-02-27 Werner Koch + + * call-dirmngr.c, call-agent.c: Add 2 more arguments to all uses + of assuan_transact. + 2002-02-25 Werner Koch * server.c (option_handler): Allow to use -2 for "send all certs diff --git a/sm/call-agent.c b/sm/call-agent.c index 54e8facb1..14e2fdf34 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -245,13 +245,13 @@ gpgsm_agent_pksign (const char *keygrip, if (digestlen*2 + 50 > DIM(line)) return seterr (General_Error); - rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL); + rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return map_assuan_err (rc); snprintf (line, DIM(line)-1, "SIGKEY %s", keygrip); line[DIM(line)-1] = 0; - rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL); + rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return map_assuan_err (rc); @@ -259,13 +259,13 @@ gpgsm_agent_pksign (const char *keygrip, p = line + strlen (line); for (i=0; i < digestlen ; i++, p += 2 ) sprintf (p, "%02X", digest[i]); - rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL); + rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return map_assuan_err (rc); init_membuf (&data, 1024); rc = assuan_transact (agent_ctx, "PKSIGN", - membuf_data_cb, &data, NULL, NULL); + membuf_data_cb, &data, NULL, NULL, NULL, NULL); if (rc) { xfree (get_membuf (&data, &len)); @@ -327,14 +327,14 @@ gpgsm_agent_pkdecrypt (const char *keygrip, if (rc) return rc; - rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL); + rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return map_assuan_err (rc); assert ( DIM(line) >= 50 ); snprintf (line, DIM(line)-1, "SETKEY %s", keygrip); line[DIM(line)-1] = 0; - rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL); + rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return map_assuan_err (rc); @@ -344,7 +344,7 @@ gpgsm_agent_pkdecrypt (const char *keygrip, cipher_parm.ciphertextlen = ciphertextlen; rc = assuan_transact (agent_ctx, "PKDECRYPT", membuf_data_cb, &data, - inq_ciphertext_cb, &cipher_parm); + inq_ciphertext_cb, &cipher_parm, NULL, NULL); if (rc) { xfree (get_membuf (&data, &len)); @@ -403,7 +403,7 @@ gpgsm_agent_genkey (KsbaConstSexp keyparms, KsbaSexp *r_pubkey) if (rc) return rc; - rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL); + rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return map_assuan_err (rc); @@ -415,7 +415,7 @@ gpgsm_agent_genkey (KsbaConstSexp keyparms, KsbaSexp *r_pubkey) return GNUPG_Invalid_Value; rc = assuan_transact (agent_ctx, "GENKEY", membuf_data_cb, &data, - inq_genkey_parms, &gk_parm); + inq_genkey_parms, &gk_parm, NULL, NULL); if (rc) { xfree (get_membuf (&data, &len)); @@ -458,7 +458,7 @@ gpgsm_agent_istrusted (KsbaCert cert) line[DIM(line)-1] = 0; xfree (fpr); - rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL); + rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); return map_assuan_err (rc); } @@ -492,7 +492,7 @@ gpgsm_agent_marktrusted (KsbaCert cert) ksba_free (dn); xfree (fpr); - rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL); + rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); return map_assuan_err (rc); } @@ -516,7 +516,7 @@ gpgsm_agent_havekey (const char *hexkeygrip) snprintf (line, DIM(line)-1, "HAVEKEY %s", hexkeygrip); line[DIM(line)-1] = 0; - rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL); + rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); return map_assuan_err (rc); } diff --git a/sm/call-dirmngr.c b/sm/call-dirmngr.c index ee41eb4ff..172a4d027 100644 --- a/sm/call-dirmngr.c +++ b/sm/call-dirmngr.c @@ -227,7 +227,8 @@ gpgsm_dirmngr_isvalid (KsbaCert cert) line[DIM(line)-1] = 0; xfree (certid); - rc = assuan_transact (dirmngr_ctx, line, NULL, NULL, inq_certificate, &parm); + rc = assuan_transact (dirmngr_ctx, line, NULL, NULL, + inq_certificate, &parm, NULL, NULL); return map_assuan_err (rc); } diff --git a/sm/server.c b/sm/server.c index ebcb7f9ad..065fc5acc 100644 --- a/sm/server.c +++ b/sm/server.c @@ -371,7 +371,7 @@ cmd_message (ASSUAN_CONTEXT ctx, char *line) /* Note that the line contains a space separated list of pappern where - each pappern is percent escaped and spacesmay be replaced by + each pappern is percent escaped and spaces may be replaced by '+'. */ static int cmd_listkeys (ASSUAN_CONTEXT ctx, char *line)