diff options
Diffstat (limited to 'agent/command.c')
-rw-r--r-- | agent/command.c | 211 |
1 files changed, 121 insertions, 90 deletions
diff --git a/agent/command.c b/agent/command.c index b682c55..940e017 100644 --- a/agent/command.c +++ b/agent/command.c @@ -975,7 +975,6 @@ cmd_genkey (assuan_context_t ctx, char *line) } - static const char hlp_readkey[] = "READKEY [--no-data] <hexstring_with_keygrip>\n" @@ -1040,20 +1039,11 @@ cmd_readkey (assuan_context_t ctx, char *line) } agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno); - if (agent_key_available (grip)) - { - /* Shadow-key is not available in our key storage. */ - rc = agent_write_shadow_key (0, grip, serialno, keyid, pkbuf, 0, - dispserialno); - } - else - { - /* Shadow-key is available in our key storage but ne check - * whether we need to update it with a new display-s/n or - * whatever. */ - rc = agent_write_shadow_key (1, grip, serialno, keyid, pkbuf, 0, - dispserialno); - } + /* Shadow-key is or is not available in our key storage. In + * any case we need to check whether we need to update with + * a new display-s/n or whatever. */ + rc = agent_write_shadow_key (grip, serialno, keyid, pkbuf, 0, 0, + dispserialno); if (rc) goto leave; @@ -1292,9 +1282,6 @@ cmd_keyinfo (assuan_context_t ctx, char *line) char hexgrip[41]; int disabled, ttl, confirm, is_ssh; - if (ctrl->restricted) - return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN)); - if (has_option (line, "--ssh-list")) list_mode = 2; else @@ -1343,6 +1330,9 @@ cmd_keyinfo (assuan_context_t ctx, char *line) char *dirname; gnupg_dirent_t dir_entry; + if (ctrl->restricted) + return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN)); + dirname = make_filename_try (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR, NULL); if (!dirname) @@ -1865,16 +1855,18 @@ cmd_learn (assuan_context_t ctx, char *line) { ctrl_t ctrl = assuan_get_pointer (ctx); gpg_error_t err; - int send, sendinfo, force; + int send, sendinfo, force, reallyforce; send = has_option (line, "--send"); sendinfo = send? 1 : has_option (line, "--sendinfo"); force = has_option (line, "--force"); + reallyforce = has_option (line, "--reallyforce"); if (ctrl->restricted) return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN)); - err = agent_handle_learn (ctrl, send, sendinfo? ctx : NULL, force); + err = agent_handle_learn (ctrl, send, sendinfo? ctx : NULL, + force, reallyforce); return leave_cmd (ctx, err); } @@ -1951,7 +1943,7 @@ cmd_passwd (assuan_context_t ctx, char *line) opt_verify? NULL : cache_nonce, ctrl->server_local->keydesc, grip, &shadow_info, CACHE_MODE_IGNORE, NULL, - &s_skey, &passphrase); + &s_skey, &passphrase, NULL); if (err) ; else if (shadow_info) @@ -2435,14 +2427,14 @@ cmd_import_key (assuan_context_t ctx, char *line) if (passphrase) { err = agent_protect (key, passphrase, &finalkey, &finalkeylen, - ctrl->s2k_count, -1); + ctrl->s2k_count); if (!err) - err = agent_write_private_key (grip, finalkey, finalkeylen, force, - opt_timestamp, NULL, NULL, NULL); + err = agent_write_private_key (grip, finalkey, finalkeylen, force, 0, + NULL, NULL, NULL, opt_timestamp); } else - err = agent_write_private_key (grip, key, realkeylen, force, - opt_timestamp, NULL, NULL, NULL); + err = agent_write_private_key (grip, key, realkeylen, force, 0, + NULL, NULL, NULL, opt_timestamp); leave: gcry_sexp_release (openpgp_sexp); @@ -2532,7 +2524,7 @@ cmd_export_key (assuan_context_t ctx, char *line) err = agent_key_from_file (ctrl, cache_nonce, ctrl->server_local->keydesc, grip, &shadow_info, CACHE_MODE_IGNORE, NULL, &s_skey, - openpgp ? &passphrase : NULL); + openpgp ? &passphrase : NULL, NULL); if (err) goto leave; if (shadow_info) @@ -2677,28 +2669,30 @@ cmd_delete_key (assuan_context_t ctx, char *line) -#if SIZEOF_TIME_T > SIZEOF_UNSIGNED_LONG -#define KEYTOCARD_TIMESTAMP_FORMAT "(10:created-at10:%010llu))" -#else -#define KEYTOCARD_TIMESTAMP_FORMAT "(10:created-at10:%010lu))" -#endif - static const char hlp_keytocard[] = - "KEYTOCARD [--force] <hexstring_with_keygrip> <serialno> <id> <timestamp>\n" - "\n"; + "KEYTOCARD [--force] <hexgrip> <serialno> <keyref> [<timestamp> [<ecdh>]]\n" + "\n" + "TIMESTAMP is required for OpenPGP and defaults to the Epoch.\n" + "ECDH are the hexified ECDH parameters for OpenPGP.\n" + "SERIALNO is used for checking; use \"-\" to disable the check."; static gpg_error_t cmd_keytocard (assuan_context_t ctx, char *line) { ctrl_t ctrl = assuan_get_pointer (ctx); int force; gpg_error_t err = 0; + char *argv[5]; + int argc; unsigned char grip[20]; + const char *serialno, *keyref; gcry_sexp_t s_skey = NULL; unsigned char *keydata; size_t keydatalen; - const char *serialno, *timestamp_str, *id; unsigned char *shadow_info = NULL; - time_t timestamp; + uint64_t timestamp; + char *ecdh_params = NULL; + unsigned int ecdh_params_len; + unsigned int extralen1, extralen2; if (ctrl->restricted) return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN)); @@ -2706,7 +2700,14 @@ cmd_keytocard (assuan_context_t ctx, char *line) force = has_option (line, "--force"); line = skip_options (line); - err = parse_keygrip (ctx, line, grip); + argc = split_fields (line, argv, DIM (argv)); + if (argc < 3) + { + err = gpg_error (GPG_ERR_MISSING_VALUE); + goto leave; + } + + err = parse_keygrip (ctx, argv[0], grip); if (err) goto leave; @@ -2716,82 +2717,112 @@ cmd_keytocard (assuan_context_t ctx, char *line) goto leave; } - /* Fixme: Replace the parsing code by split_fields(). */ - line += 40; - while (*line && (*line == ' ' || *line == '\t')) - line++; - serialno = line; - while (*line && (*line != ' ' && *line != '\t')) - line++; - if (!*line) - { - err = gpg_error (GPG_ERR_MISSING_VALUE); - goto leave; - } - *line = '\0'; - line++; - while (*line && (*line == ' ' || *line == '\t')) - line++; - id = line; - while (*line && (*line != ' ' && *line != '\t')) - line++; - if (!*line) - { - err = gpg_error (GPG_ERR_MISSING_VALUE); - goto leave; - } - *line = '\0'; - line++; - while (*line && (*line == ' ' || *line == '\t')) - line++; - timestamp_str = line; - while (*line && (*line != ' ' && *line != '\t')) - line++; - if (*line) - *line = '\0'; + /* Note that checking of the s/n is currently not implemented but we + * want to provide a clean interface if we ever implement it. */ + serialno = argv[1]; + if (!strcmp (serialno, "-")) + serialno = NULL; - if ((timestamp = isotime2epoch (timestamp_str)) == (time_t)(-1)) - { - err = gpg_error (GPG_ERR_INV_TIME); - goto leave; - } + keyref = argv[2]; err = agent_key_from_file (ctrl, NULL, ctrl->server_local->keydesc, grip, &shadow_info, CACHE_MODE_IGNORE, NULL, - &s_skey, NULL); + &s_skey, NULL, ×tamp); if (err) + goto leave; + + if (shadow_info) { - xfree (shadow_info); + /* Key is already on a smartcard - wer can't extract it. */ + err = gpg_error (GPG_ERR_UNUSABLE_SECKEY); goto leave; } - if (shadow_info) + + /* Default to the creation time as stored in the private key. The + * parameter is here so that gpg can make sure that the timestamp is + * used. It is also important for OpenPGP cards to allow computing + * of the fingerprint. Same goes for the ECDH params. */ + if (argc > 3) { - /* Key is on a smartcard already. */ - xfree (shadow_info); - gcry_sexp_release (s_skey); - err = gpg_error (GPG_ERR_UNUSABLE_SECKEY); + timestamp = isotime2epoch_u64 (argv[3]); + if (argc > 4) + { + size_t n; + + err = parse_hexstring (ctx, argv[4], &n); + if (err) + goto leave; /* Badly formatted ecdh params. */ + n /= 2; + if (n < 4) + { + err = set_error (GPG_ERR_ASS_PARAMETER, "ecdh param too short"); + goto leave; + } + ecdh_params_len = n; + ecdh_params = xtrymalloc (ecdh_params_len); + if (!ecdh_params) + { + err = gpg_error_from_syserror (); + goto leave; + } + if (hex2bin (argv[4], ecdh_params, ecdh_params_len) < 0) + { + err = set_error (GPG_ERR_BUG, "hex2bin"); + goto leave; + } + } + } + else if (timestamp == (uint64_t)(-1)) + timestamp = isotime2epoch_u64 ("19700101T000000"); + + if (timestamp == (uint64_t)(-1)) + { + err = gpg_error (GPG_ERR_INV_TIME); goto leave; } - keydatalen = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0); - keydata = xtrymalloc_secure (keydatalen + 30); + /* Note: We can't use make_canon_sexp because we need to allocate a + * few extra bytes for our hack below. The 20 for extralen2 + * accounts for the sexp length of ecdh_params. */ + keydatalen = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0); + extralen1 = 30; + extralen2 = ecdh_params? (20+20+ecdh_params_len) : 0; + keydata = xtrymalloc_secure (keydatalen + extralen1 + extralen2); if (keydata == NULL) { err = gpg_error_from_syserror (); - gcry_sexp_release (s_skey); goto leave; } - gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, keydata, keydatalen); gcry_sexp_release (s_skey); + s_skey = NULL; + keydatalen--; /* Decrement for last '\0'. */ - /* Add timestamp "created-at" in the private key */ - snprintf (keydata+keydatalen-1, 30, KEYTOCARD_TIMESTAMP_FORMAT, timestamp); + + /* Hack to insert the timestamp "created-at" into the private key. */ + snprintf (keydata+keydatalen-1, extralen1, "(10:created-at10:%010llu))", + (unsigned long long)timestamp); keydatalen += 10 + 19 - 1; - err = divert_writekey (ctrl, force, serialno, id, keydata, keydatalen); + + /* Hack to insert the timestamp "ecdh-params" into the private key. */ + if (ecdh_params) + { + snprintf (keydata+keydatalen-1, extralen2, "(11:ecdh-params%u:", + ecdh_params_len); + keydatalen += strlen (keydata+keydatalen-1) -1; + memcpy (keydata+keydatalen, ecdh_params, ecdh_params_len); + keydatalen += ecdh_params_len; + memcpy (keydata+keydatalen, "))", 3); + keydatalen += 2; + } + + err = divert_writekey (ctrl, force, serialno, keyref, keydata, keydatalen); xfree (keydata); leave: + xfree (ecdh_params); + gcry_sexp_release (s_skey); + xfree (shadow_info); return leave_cmd (ctx, err); } |