diff options
author | Werner Koch <[email protected]> | 2010-06-17 15:44:44 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2010-06-17 15:44:44 +0000 |
commit | 006fd75aea5cc766bc223e435e5a07b543d658d3 (patch) | |
tree | 2f4365e73bf0a8b5272426fcf1fde9b75be4002e /agent | |
parent | Add makefiles to build a w32 development package. (diff) | |
download | gnupg-006fd75aea5cc766bc223e435e5a07b543d658d3.tar.gz gnupg-006fd75aea5cc766bc223e435e5a07b543d658d3.zip |
Avoid using the protect-tool to import pkcs#12.
Diffstat (limited to 'agent')
-rw-r--r-- | agent/ChangeLog | 26 | ||||
-rw-r--r-- | agent/Makefile.am | 3 | ||||
-rw-r--r-- | agent/agent.h | 2 | ||||
-rw-r--r-- | agent/command.c | 278 | ||||
-rw-r--r-- | agent/findkey.c | 6 | ||||
-rw-r--r-- | agent/genkey.c | 199 | ||||
-rw-r--r-- | agent/minip12.c | 2360 | ||||
-rw-r--r-- | agent/minip12.h | 36 | ||||
-rw-r--r-- | agent/preset-passphrase.c | 1 | ||||
-rw-r--r-- | agent/protect-tool.c | 19 | ||||
-rw-r--r-- | agent/protect.c | 2 |
11 files changed, 354 insertions, 2578 deletions
diff --git a/agent/ChangeLog b/agent/ChangeLog index 91dd3acf3..7ea18d943 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,29 @@ +2010-06-15 Werner Koch <[email protected]> + + * command.c (cmd_keywrap_key, cmd_import_key): New. + + * genkey.c (agent_genkey, agent_protect_and_store): Factor common + code out to... + (agent_ask_new_passphrase): .. new. + + * findkey.c (agent_write_private_key): Return GPG_ERR_EEXIST + instead of GPG_ERR_GENERAL. + +2010-06-14 Werner Koch <[email protected]> + + * protect-tool.c: Remove commands --p12-import and --p12-export. + * minip12.c, minip12.h: Move to ../sm. + * Makefile.am (gpg_protect_tool_SOURCES): Remove them. + * preset-passphrase.c: Remove unneeded minip12.h. + + * command.c (cmd_keywrap_key): New. + + * command.c (leave_cmd): New. + (cmd_istrusted, cmd_listtrusted, cmd_marktrusted, cmd_pksign) + (cmd_pkdecrypt, cmd_genkey, cmd_readkey, cmd_keyinfo) + (cmd_get_passphrase, cmd_get_confirmation, cmd_learn) + (cmd_passwd, cmd_preset_passphrase, cmd_getval, cmd_putval): Use it. + 2010-05-12 Werner Koch <[email protected]> * preset-passphrase.c (forget_passphrase): Actually implement diff --git a/agent/Makefile.am b/agent/Makefile.am index 9258fc86d..e22153681 100644 --- a/agent/Makefile.am +++ b/agent/Makefile.am @@ -79,8 +79,7 @@ gpg_agent_DEPENDENCIES = $(gpg_agent_res_deps) gpg_protect_tool_SOURCES = \ protect-tool.c \ - protect.c \ - minip12.c minip12.h + protect.c gpg_protect_tool_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) gpg_protect_tool_LDADD = $(common_libs) $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) \ diff --git a/agent/agent.h b/agent/agent.h index 09519d48b..b39f2325c 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -284,6 +284,8 @@ int agent_pkdecrypt (ctrl_t ctrl, const char *desc_text, /*-- genkey.c --*/ int check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent); +gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt, + char **r_passphrase); int agent_genkey (ctrl_t ctrl, const char *keyparam, size_t keyparmlen, membuf_t *outbuf); int agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey); diff --git a/agent/command.c b/agent/command.c index 082e730bd..9bd5ce5c3 100644 --- a/agent/command.c +++ b/agent/command.c @@ -38,10 +38,14 @@ #include <assuan.h> #include "i18n.h" -/* maximum allowed size of the inquired ciphertext */ +/* Maximum allowed size of the inquired ciphertext. */ #define MAXLEN_CIPHERTEXT 4096 -/* maximum allowed size of the key parameters */ +/* Maximum allowed size of the key parameters. */ #define MAXLEN_KEYPARAM 1024 +/* Maximum allowed size of key data as used in inquiries (bytes). */ +#define MAXLEN_KEYDATA 4096 +/* The size of the import/export KEK key (in bytes). */ +#define KEYWRAP_KEYSIZE (128/8) #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t)) @@ -63,6 +67,8 @@ struct server_local_s the end of this session. */ int allow_pinentry_notify; /* Set if pinentry notifications should be done. */ + void *import_key; /* Malloced KEK for the import_key command. */ + void *export_key; /* Malloced KEK for the export_key command. */ }; @@ -340,6 +346,26 @@ agent_inq_pinentry_launched (ctrl_t ctrl, unsigned long pid) } +/* Helper to print a message while leaving a command. */ +static gpg_error_t +leave_cmd (assuan_context_t ctx, gpg_error_t err) +{ + if (err) + { + const char *name = assuan_get_command_name (ctx); + if (!name) + name = "?"; + if (gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT) + log_error ("command '%s' failed: %s\n", name, + gpg_strerror (err)); + else + log_error ("command '%s' failed: %s <%s>\n", name, + gpg_strerror (err), gpg_strsource (err)); + } + return err; +} + + static const char hlp_geteventcounter[] = "GETEVENTCOUNTER\n" @@ -432,10 +458,7 @@ cmd_istrusted (assuan_context_t ctx, char *line) else if (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF ) return gpg_error (GPG_ERR_NOT_TRUSTED); else - { - log_error ("command is_trusted failed: %s\n", gpg_strerror (rc)); - return rc; - } + return leave_cmd (ctx, rc); } @@ -451,9 +474,7 @@ cmd_listtrusted (assuan_context_t ctx, char *line) (void)line; rc = agent_listtrusted (ctx); - if (rc) - log_error ("command listtrusted failed: %s\n", gpg_strerror (rc)); - return rc; + return leave_cmd (ctx, rc); } @@ -494,9 +515,7 @@ cmd_marktrusted (assuan_context_t ctx, char *line) p++; rc = agent_marktrusted (ctrl, p, fpr, flag); - if (rc) - log_error ("command marktrusted failed: %s\n", gpg_strerror (rc)); - return rc; + return leave_cmd (ctx, rc); } @@ -695,11 +714,9 @@ cmd_pksign (assuan_context_t ctx, char *line) clear_outbuf (&outbuf); else rc = write_and_clear_outbuf (ctx, &outbuf); - if (rc) - log_error ("command pksign failed: %s\n", gpg_strerror (rc)); xfree (ctrl->server_local->keydesc); ctrl->server_local->keydesc = NULL; - return rc; + return leave_cmd (ctx, rc); } @@ -734,11 +751,9 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line) clear_outbuf (&outbuf); else rc = write_and_clear_outbuf (ctx, &outbuf); - if (rc) - log_error ("command pkdecrypt failed: %s\n", gpg_strerror (rc)); xfree (ctrl->server_local->keydesc); ctrl->server_local->keydesc = NULL; - return rc; + return leave_cmd (ctx, rc); } @@ -780,9 +795,7 @@ cmd_genkey (assuan_context_t ctx, char *line) clear_outbuf (&outbuf); else rc = write_and_clear_outbuf (ctx, &outbuf); - if (rc) - log_error ("command genkey failed: %s\n", gpg_strerror (rc)); - return rc; + return leave_cmd (ctx, rc); } @@ -825,9 +838,7 @@ cmd_readkey (assuan_context_t ctx, char *line) gcry_sexp_release (s_pkey); } - if (rc) - log_error ("command readkey failed: %s\n", gpg_strerror (rc)); - return rc; + return leave_cmd (ctx, rc); } @@ -967,7 +978,7 @@ cmd_keyinfo (assuan_context_t ctx, char *line) if (dir) closedir (dir); if (err && gpg_err_code (err) != GPG_ERR_NOT_FOUND) - log_error ("command keyinfo failed: %s\n", gpg_strerror (err)); + leave_cmd (ctx, err); return err; } @@ -1167,9 +1178,7 @@ cmd_get_passphrase (assuan_context_t ctx, char *line) } } - if (rc) - log_error ("command get_passphrase failed: %s\n", gpg_strerror (rc)); - return rc; + return leave_cmd (ctx, rc); } @@ -1240,9 +1249,7 @@ cmd_get_confirmation (assuan_context_t ctx, char *line) plus_to_blank (desc); rc = agent_get_confirmation (ctrl, desc, NULL, NULL, 0); - if (rc) - log_error ("command get_confirmation failed: %s\n", gpg_strerror (rc)); - return rc; + return leave_cmd (ctx, rc); } @@ -1259,9 +1266,7 @@ cmd_learn (assuan_context_t ctx, char *line) int rc; rc = agent_handle_learn (ctrl, has_option (line, "--send")? ctx : NULL); - if (rc) - log_error ("command learn failed: %s\n", gpg_strerror (rc)); - return rc; + return leave_cmd (ctx, rc); } @@ -1304,9 +1309,7 @@ cmd_passwd (assuan_context_t ctx, char *line) leave: gcry_sexp_release (s_skey); xfree (shadow_info); - if (rc) - log_error ("command passwd failed: %s\n", gpg_strerror (rc)); - return rc; + return leave_cmd (ctx, rc); } @@ -1371,10 +1374,7 @@ cmd_preset_passphrase (assuan_context_t ctx, char *line) if (!rc) rc = agent_put_cache (grip_clear, CACHE_MODE_ANY, passphrase, ttl); - if (rc) - log_error ("command preset_passphrase failed: %s\n", gpg_strerror (rc)); - - return rc; + return leave_cmd (ctx, rc); } @@ -1397,6 +1397,186 @@ cmd_scd (assuan_context_t ctx, char *line) +static const char hlp_keywrap_key[] = + "KEYWRAP_KEY [--clear] <mode>\n" + "\n" + "Return a key to wrap another key. For now the key is returned\n" + "verbatim and and thus makes not much sense because an eavesdropper on\n" + "the gpg-agent connection will see the key as well as the wrapped key.\n" + "However, this function may either be equipped with a public key\n" + "mechanism or not used at all if the key is a pre-shared key. In any\n" + "case wrapping the import and export of keys is a requirement for\n" + "certain cryptographic validations and thus useful. The key persists\n" + "a RESET command but may be cleared using the option --clear.\n" + "\n" + "Supported modes are:\n" + " --import - Return a key to import a key into gpg-agent\n" + " --export - Return a key to export a key from gpg-agent"; +static gpg_error_t +cmd_keywrap_key (assuan_context_t ctx, char *line) +{ + ctrl_t ctrl = assuan_get_pointer (ctx); + gpg_error_t err = 0; + int clearopt = has_option (line, "--clear"); + + + assuan_begin_confidential (ctx); + if (has_option (line, "--import")) + { + xfree (ctrl->server_local->import_key); + if (clearopt) + ctrl->server_local->import_key = NULL; + else if (!(ctrl->server_local->import_key = + gcry_random_bytes (KEYWRAP_KEYSIZE, GCRY_STRONG_RANDOM))) + err = gpg_error_from_syserror (); + else + err = assuan_send_data (ctx, ctrl->server_local->import_key, + KEYWRAP_KEYSIZE); + } + else if (has_option (line, "--export")) + { + xfree (ctrl->server_local->export_key); + if (clearopt) + ctrl->server_local->export_key = NULL; + else if (!(ctrl->server_local->export_key = + gcry_random_bytes (KEYWRAP_KEYSIZE, GCRY_STRONG_RANDOM))) + err = gpg_error_from_syserror (); + else + err = assuan_send_data (ctx, ctrl->server_local->export_key, + KEYWRAP_KEYSIZE); + } + else + err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for MODE"); + assuan_end_confidential (ctx); + + return leave_cmd (ctx, err); +} + + + +static const char hlp_import_key[] = + "IMPORT_KEY\n" + "\n" + "Import a secret key into the key store. The key is expected to be\n" + "encrypted using the current session's key wrapping key (cf. command\n" + "KEYWRAP_KEY) using the AESWRAP-128 algorithm. This function takes\n" + "no arguments but uses the inquiry \"KEYDATA\" to ask for the actual\n" + "key data. The unwrapped key must be a canonical S-expression."; +static gpg_error_t +cmd_import_key (assuan_context_t ctx, char *line) +{ + ctrl_t ctrl = assuan_get_pointer (ctx); + gpg_error_t err; + unsigned char *wrappedkey = NULL; + size_t wrappedkeylen; + gcry_cipher_hd_t cipherhd = NULL; + unsigned char *key = NULL; + size_t keylen, realkeylen; + char *passphrase = NULL; + unsigned char *finalkey = NULL; + size_t finalkeylen; + unsigned char grip[20]; + + (void)line; + + if (!ctrl->server_local->import_key) + { + err = gpg_error (GPG_ERR_BAD_KEY); + goto leave; + } + + assuan_begin_confidential (ctx); + err = assuan_inquire (ctx, "KEYDATA", + &wrappedkey, &wrappedkeylen, MAXLEN_KEYDATA); + assuan_end_confidential (ctx); + if (err) + goto leave; + if (wrappedkeylen < 24) + { + err = gpg_error (GPG_ERR_INV_LENGTH); + goto leave; + } + keylen = wrappedkeylen - 8; + key = xtrymalloc_secure (keylen); + if (!key) + { + err = gpg_error_from_syserror (); + goto leave; + } + + err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128, + GCRY_CIPHER_MODE_AESWRAP, 0); + if (err) + goto leave; + err = gcry_cipher_setkey (cipherhd, + ctrl->server_local->import_key, KEYWRAP_KEYSIZE); + if (err) + goto leave; + err = gcry_cipher_decrypt (cipherhd, key, keylen, wrappedkey, wrappedkeylen); + if (err) + goto leave; + gcry_cipher_close (cipherhd); + cipherhd = NULL; + xfree (wrappedkey); + wrappedkey = NULL; + + realkeylen = gcry_sexp_canon_len (key, keylen, NULL, &err); + if (!realkeylen) + goto leave; /* Invalid canonical encoded S-expression. */ + + err = keygrip_from_canon_sexp (key, realkeylen, grip); + if (err) + goto leave; + + if (!agent_key_available (grip)) + { + err = gpg_error (GPG_ERR_EEXIST); + goto leave; + } + + err = agent_ask_new_passphrase + (ctrl, _("Please enter the passphrase to protect the " + "imported object within the GnuPG system."), + &passphrase); + if (err) + goto leave; + + if (passphrase) + { + err = agent_protect (key, passphrase, &finalkey, &finalkeylen); + if (!err) + err = agent_write_private_key (grip, finalkey, finalkeylen, 0); + } + else + err = agent_write_private_key (grip, key, realkeylen, 0); + + leave: + xfree (finalkey); + xfree (passphrase); + xfree (key); + gcry_cipher_close (cipherhd); + xfree (wrappedkey); + return leave_cmd (ctx, err); +} + + + +static const char hlp_export_key[] = + "EXPORT_KEY\n" + "\n"; +static gpg_error_t +cmd_export_key (assuan_context_t ctx, char *line) +{ + gpg_error_t err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + + /* leave: */ + return leave_cmd (ctx, err); +} + + + + static const char hlp_getval[] = "GETVAL <key>\n" "\n" @@ -1435,9 +1615,7 @@ cmd_getval (assuan_context_t ctx, char *line) else return gpg_error (GPG_ERR_NO_DATA); - if (rc) - log_error ("command getval failed: %s\n", gpg_strerror (rc)); - return rc; + return leave_cmd (ctx, rc); } @@ -1520,9 +1698,7 @@ cmd_putval (assuan_context_t ctx, char *line) } } - if (rc) - log_error ("command putval failed: %s\n", gpg_strerror (rc)); - return rc; + return leave_cmd (ctx, rc); } @@ -1641,7 +1817,7 @@ static const char hlp_getinfo[] = " std_session_env - List the standard session environment.\n" " std_startup_env - List the standard startup environment.\n" " cmd_has_option\n" - " - Returns OK if the command CMD implements the option OPT."; + " - Returns OK if the command CMD implements the option OPT\n."; static gpg_error_t cmd_getinfo (assuan_context_t ctx, char *line) { @@ -1910,6 +2086,9 @@ register_commands (assuan_context_t ctx) { "INPUT", NULL }, { "OUTPUT", NULL }, { "SCD", cmd_scd, hlp_scd }, + { "KEYWRAP_KEY", cmd_keywrap_key, hlp_keywrap_key }, + { "IMPORT_KEY", cmd_import_key, hlp_import_key }, + { "EXPORT_KEY", cmd_export_key, hlp_export_key }, { "GETVAL", cmd_getval, hlp_getval }, { "PUTVAL", cmd_putval, hlp_putval }, { "UPDATESTARTUPTTY", cmd_updatestartuptty, hlp_updatestartuptty }, @@ -2021,6 +2200,9 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd) /* Cleanup. */ assuan_release (ctx); + xfree (ctrl->server_local->keydesc); + xfree (ctrl->server_local->import_key); + xfree (ctrl->server_local->export_key); if (ctrl->server_local->stopme) agent_exit (0); xfree (ctrl->server_local); diff --git a/agent/findkey.c b/agent/findkey.c index d6478ac4d..db610c15a 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -69,7 +69,7 @@ agent_write_private_key (const unsigned char *grip, { log_error ("secret key file `%s' already exists\n", fname); xfree (fname); - return gpg_error (GPG_ERR_GENERAL); + return gpg_error (GPG_ERR_EEXIST); } /* FIXME: On POSIX systems we used include S_IRGRP as well. */ @@ -883,8 +883,8 @@ agent_public_key_from_file (ctrl_t ctrl, -/* Return the secret key as an S-Exp after locating it using the grip. - Returns NULL if key is not available. 0 = key is available */ +/* Check whether the the secret key identified by GRIP is available. + Returns 0 is the key is available. */ int agent_key_available (const unsigned char *grip) { diff --git a/agent/genkey.c b/agent/genkey.c index c5d2c9e33..7c6b44b96 100644 --- a/agent/genkey.c +++ b/agent/genkey.c @@ -1,5 +1,5 @@ /* genkey.c - Generate a keypair - * Copyright (C) 2002, 2003, 2004, 2007 Free Software Foundation, Inc. + * Copyright (C) 2002, 2003, 2004, 2007, 2010 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -286,6 +286,69 @@ reenter_compare_cb (struct pin_entry_info_s *pi) } +/* Ask the user for a new passphrase using PROMPT. On success the + function returns 0 and store the passphrase at R_PASSPHRASE; if the + user opted not to use a passphrase NULL will be stored there. The + user needs to free the returned string. In case of an error and + error code is returned and NULL stored at R_PASSPHRASE. */ +gpg_error_t +agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt, + char **r_passphrase) +{ + gpg_error_t err; + const char *text1 = prompt; + const char *text2 = _("Please re-enter this passphrase"); + const char *initial_errtext = NULL; + struct pin_entry_info_s *pi, *pi2; + + *r_passphrase = NULL; + + pi = gcry_calloc_secure (2, sizeof (*pi) + 100); + pi2 = pi + (sizeof *pi + 100); + pi->max_length = 100; + pi->max_tries = 3; + pi->with_qualitybar = 1; + pi2->max_length = 100; + pi2->max_tries = 3; + pi2->check_cb = reenter_compare_cb; + pi2->check_cb_arg = pi->pin; + + next_try: + err = agent_askpin (ctrl, text1, NULL, initial_errtext, pi); + initial_errtext = NULL; + if (!err) + { + if (check_passphrase_constraints (ctrl, pi->pin, 0)) + { + pi->failed_tries = 0; + pi2->failed_tries = 0; + goto next_try; + } + /* Unless the passphrase is empty, ask to confirm it. */ + if (pi->pin && *pi->pin) + { + err = agent_askpin (ctrl, text2, NULL, NULL, pi2); + if (err == -1) + { /* The re-entered one did not match and the user did not + hit cancel. */ + initial_errtext = _("does not match - try again"); + goto next_try; + } + } + } + + if (!err && *pi->pin) + { + /* User wants a passphrase. */ + *r_passphrase = xtrystrdup (pi->pin); + if (!*r_passphrase) + err = gpg_error_from_syserror (); + } + xfree (pi); + return err; +} + + /* Generate a new keypair according to the parameters given in KEYPARAM */ @@ -294,7 +357,7 @@ agent_genkey (ctrl_t ctrl, const char *keyparam, size_t keyparamlen, membuf_t *outbuf) { gcry_sexp_t s_keyparam, s_key, s_private, s_public; - struct pin_entry_info_s *pi, *pi2; + char *passphrase = NULL; int rc; size_t len; char *buf; @@ -307,63 +370,19 @@ agent_genkey (ctrl_t ctrl, const char *keyparam, size_t keyparamlen, } /* Get the passphrase now, cause key generation may take a while. */ - { - const char *text1 = _("Please enter the passphrase to%0A" - "to protect your new key"); - const char *text2 = _("Please re-enter this passphrase"); - const char *initial_errtext = NULL; - - pi = gcry_calloc_secure (2, sizeof (*pi) + 100); - pi2 = pi + (sizeof *pi + 100); - pi->max_length = 100; - pi->max_tries = 3; - pi->with_qualitybar = 1; - pi2->max_length = 100; - pi2->max_tries = 3; - pi2->check_cb = reenter_compare_cb; - pi2->check_cb_arg = pi->pin; - - next_try: - rc = agent_askpin (ctrl, text1, NULL, initial_errtext, pi); - initial_errtext = NULL; - if (!rc) - { - if (check_passphrase_constraints (ctrl, pi->pin, 0)) - { - pi->failed_tries = 0; - pi2->failed_tries = 0; - goto next_try; - } - if (pi->pin && *pi->pin) - { - rc = agent_askpin (ctrl, text2, NULL, NULL, pi2); - if (rc == -1) - { /* The re-entered one did not match and the user did not - hit cancel. */ - initial_errtext = _("does not match - try again"); - goto next_try; - } - } - } - if (rc) - { - xfree (pi); - return rc; - } - - if (!*pi->pin) - { - xfree (pi); - pi = NULL; /* User does not want a passphrase. */ - } - } + rc = agent_ask_new_passphrase (ctrl, + _("Please enter the passphrase to%0A" + "to protect your new key"), + &passphrase); + if (rc) + return rc; rc = gcry_pk_genkey (&s_key, s_keyparam ); gcry_sexp_release (s_keyparam); if (rc) { log_error ("key generation failed: %s\n", gpg_strerror (rc)); - xfree (pi); + xfree (passphrase); return rc; } @@ -373,7 +392,7 @@ agent_genkey (ctrl_t ctrl, const char *keyparam, size_t keyparamlen, { log_error ("key generation failed: invalid return value\n"); gcry_sexp_release (s_key); - xfree (pi); + xfree (passphrase); return gpg_error (GPG_ERR_INV_DATA); } s_public = gcry_sexp_find_token (s_key, "public-key", 0); @@ -382,7 +401,7 @@ agent_genkey (ctrl_t ctrl, const char *keyparam, size_t keyparamlen, log_error ("key generation failed: invalid return value\n"); gcry_sexp_release (s_private); gcry_sexp_release (s_key); - xfree (pi); + xfree (passphrase); return gpg_error (GPG_ERR_INV_DATA); } gcry_sexp_release (s_key); s_key = NULL; @@ -390,8 +409,9 @@ agent_genkey (ctrl_t ctrl, const char *keyparam, size_t keyparamlen, /* store the secret key */ if (DBG_CRYPTO) log_debug ("storing private key\n"); - rc = store_key (s_private, pi? pi->pin:NULL, 0); - xfree (pi); pi = NULL; + rc = store_key (s_private, passphrase, 0); + xfree (passphrase); + passphrase = NULL; gcry_sexp_release (s_private); if (rc) { @@ -423,65 +443,20 @@ agent_genkey (ctrl_t ctrl, const char *keyparam, size_t keyparamlen, -/* Apply a new passpahrse to the key S_SKEY and store it. */ +/* Apply a new passphrase to the key S_SKEY and store it. */ int agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey) { - struct pin_entry_info_s *pi, *pi2; int rc; + char *passphrase; - { - const char *text1 = _("Please enter the new passphrase"); - const char *text2 = _("Please re-enter this passphrase"); - const char *initial_errtext = NULL; - - pi = gcry_calloc_secure (2, sizeof (*pi) + 100); - pi2 = pi + (sizeof *pi + 100); - pi->max_length = 100; - pi->max_tries = 3; - pi->with_qualitybar = 1; - pi2->max_length = 100; - pi2->max_tries = 3; - pi2->check_cb = reenter_compare_cb; - pi2->check_cb_arg = pi->pin; - - next_try: - rc = agent_askpin (ctrl, text1, NULL, initial_errtext, pi); - initial_errtext = NULL; - if (!rc) - { - if (check_passphrase_constraints (ctrl, pi->pin, 0)) - { - pi->failed_tries = 0; - pi2->failed_tries = 0; - goto next_try; - } - /* Unless the passphrase is empty, ask to confirm it. */ - if (pi->pin && *pi->pin) - { - rc = agent_askpin (ctrl, text2, NULL, NULL, pi2); - if (rc == -1) - { /* The re-entered one did not match and the user did not - hit cancel. */ - initial_errtext = _("does not match - try again"); - goto next_try; - } - } - } - if (rc) - { - xfree (pi); - return rc; - } - - if (!*pi->pin) - { - xfree (pi); - pi = NULL; /* User does not want a passphrase. */ - } - } - - rc = store_key (s_skey, pi? pi->pin:NULL, 1); - xfree (pi); + rc = agent_ask_new_passphrase (ctrl, + _("Please enter the new passphrase"), + &passphrase); + if (!rc) + { + rc = store_key (s_skey, passphrase, 1); + xfree (passphrase); + } return rc; } diff --git a/agent/minip12.c b/agent/minip12.c deleted file mode 100644 index 6f512e9e5..000000000 --- a/agent/minip12.c +++ /dev/null @@ -1,2360 +0,0 @@ -/* minip12.c - A minimal pkcs-12 implementation. - * Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include <gcrypt.h> -#include <errno.h> - -#ifdef TEST -#include <sys/stat.h> -#include <unistd.h> -#endif - -#include "../common/logging.h" -#include "../common/utf8conv.h" -#include "minip12.h" - -#ifndef DIM -#define DIM(v) (sizeof(v)/sizeof((v)[0])) -#endif - - -enum -{ - UNIVERSAL = 0, - APPLICATION = 1, - ASNCONTEXT = 2, - PRIVATE = 3 -}; - - -enum -{ - TAG_NONE = 0, - TAG_BOOLEAN = 1, - TAG_INTEGER = 2, - TAG_BIT_STRING = 3, - TAG_OCTET_STRING = 4, - TAG_NULL = 5, - TAG_OBJECT_ID = 6, - TAG_OBJECT_DESCRIPTOR = 7, - TAG_EXTERNAL = 8, - TAG_REAL = 9, - TAG_ENUMERATED = 10, - TAG_EMBEDDED_PDV = 11, - TAG_UTF8_STRING = 12, - TAG_REALTIVE_OID = 13, - TAG_SEQUENCE = 16, - TAG_SET = 17, - TAG_NUMERIC_STRING = 18, - TAG_PRINTABLE_STRING = 19, - TAG_TELETEX_STRING = 20, - TAG_VIDEOTEX_STRING = 21, - TAG_IA5_STRING = 22, - TAG_UTC_TIME = 23, - TAG_GENERALIZED_TIME = 24, - TAG_GRAPHIC_STRING = 25, - TAG_VISIBLE_STRING = 26, - TAG_GENERAL_STRING = 27, - TAG_UNIVERSAL_STRING = 28, - TAG_CHARACTER_STRING = 29, - TAG_BMP_STRING = 30 -}; - - -static unsigned char const oid_data[9] = { - 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 }; -static unsigned char const oid_encryptedData[9] = { - 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x06 }; -static unsigned char const oid_pkcs_12_keyBag[11] = { - 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x0A, 0x01, 0x01 }; -static unsigned char const oid_pkcs_12_pkcs_8ShroudedKeyBag[11] = { - 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x0A, 0x01, 0x02 }; -static unsigned char const oid_pkcs_12_CertBag[11] = { - 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x0A, 0x01, 0x03 }; -static unsigned char const oid_pkcs_12_CrlBag[11] = { - 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x0A, 0x01, 0x04 }; - -static unsigned char const oid_pbeWithSHAAnd3_KeyTripleDES_CBC[10] = { - 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x01, 0x03 }; -static unsigned char const oid_pbeWithSHAAnd40BitRC2_CBC[10] = { - 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x01, 0x06 }; -static unsigned char const oid_x509Certificate_for_pkcs_12[10] = { - 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x16, 0x01 }; - - -static unsigned char const oid_rsaEncryption[9] = { - 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 }; - - -static unsigned char const data_3desiter2048[30] = { - 0x30, 0x1C, 0x06, 0x0A, 0x2A, 0x86, 0x48, 0x86, - 0xF7, 0x0D, 0x01, 0x0C, 0x01, 0x03, 0x30, 0x0E, - 0x04, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x02, 0x02, 0x08, 0x00 }; -#define DATA_3DESITER2048_SALT_OFF 18 - -static unsigned char const data_rc2iter2048[30] = { - 0x30, 0x1C, 0x06, 0x0A, 0x2A, 0x86, 0x48, 0x86, - 0xF7, 0x0D, 0x01, 0x0C, 0x01, 0x06, 0x30, 0x0E, - 0x04, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x02, 0x02, 0x08, 0x00 }; -#define DATA_RC2ITER2048_SALT_OFF 18 - -static unsigned char const data_mactemplate[51] = { - 0x30, 0x31, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, - 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, - 0x14, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x04, 0x08, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, - 0x02, 0x08, 0x00 }; -#define DATA_MACTEMPLATE_MAC_OFF 17 -#define DATA_MACTEMPLATE_SALT_OFF 39 - -static unsigned char const data_attrtemplate[106] = { - 0x31, 0x7c, 0x30, 0x55, 0x06, 0x09, 0x2a, 0x86, - 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x14, 0x31, - 0x48, 0x1e, 0x46, 0x00, 0x47, 0x00, 0x6e, 0x00, - 0x75, 0x00, 0x50, 0x00, 0x47, 0x00, 0x20, 0x00, - 0x65, 0x00, 0x78, 0x00, 0x70, 0x00, 0x6f, 0x00, - 0x72, 0x00, 0x74, 0x00, 0x65, 0x00, 0x64, 0x00, - 0x20, 0x00, 0x63, 0x00, 0x65, 0x00, 0x72, 0x00, - 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00, - 0x63, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, - 0x20, 0x00, 0x66, 0x00, 0x66, 0x00, 0x66, 0x00, - 0x66, 0x00, 0x66, 0x00, 0x66, 0x00, 0x66, 0x00, - 0x66, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, - 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31, 0x16, - 0x04, 0x14 }; /* Need to append SHA-1 digest. */ -#define DATA_ATTRTEMPLATE_KEYID_OFF 73 - -struct buffer_s -{ - unsigned char *buffer; - size_t length; -}; - - -struct tag_info -{ - int class; - int is_constructed; - unsigned long tag; - unsigned long length; /* length part of the TLV */ - int nhdr; - int ndef; /* It is an indefinite length */ -}; - - -/* Parse the buffer at the address BUFFER which is of SIZE and return - the tag and the length part from the TLV triplet. Update BUFFER - and SIZE on success. Checks that the encoded length does not - exhaust the length of the provided buffer. */ -static int -parse_tag (unsigned char const **buffer, size_t *size, struct tag_info *ti) -{ - int c; - unsigned long tag; - const unsigned char *buf = *buffer; - size_t length = *size; - - ti->length = 0; - ti->ndef = 0; - ti->nhdr = 0; - - /* Get the tag */ - if (!length) - return -1; /* premature eof */ - c = *buf++; length--; - ti->nhdr++; - - ti->class = (c & 0xc0) >> 6; - ti->is_constructed = !!(c & 0x20); - tag = c & 0x1f; - - if (tag == 0x1f) - { - tag = 0; - do - { - tag <<= 7; - if (!length) - return -1; /* premature eof */ - c = *buf++; length--; - ti->nhdr++; - tag |= c & 0x7f; - } - while (c & 0x80); - } - ti->tag = tag; - - /* Get the length */ - if (!length) - return -1; /* prematureeof */ - c = *buf++; length--; - ti->nhdr++; - - if ( !(c & 0x80) ) - ti->length = c; - else if (c == 0x80) - ti->ndef = 1; - else if (c == 0xff) - return -1; /* forbidden length value */ - else - { - unsigned long len = 0; - int count = c & 0x7f; - - for (; count; count--) - { - len <<= 8; - if (!length) - return -1; /* premature_eof */ - c = *buf++; length--; - ti->nhdr++; - len |= c & 0xff; - } - ti->length = len; - } - - if (ti->class == UNIVERSAL && !ti->tag) - ti->length = 0; - - if (ti->length > length) - return -1; /* data larger than buffer. */ - - *buffer = buf; - *size = length; - return 0; -} - - -/* Given an ASN.1 chunk of a structure like: - - 24 NDEF: OCTET STRING -- This is not passed to us - 04 1: OCTET STRING -- INPUT point s to here - : 30 - 04 1: OCTET STRING - : 80 - [...] - 04 2: OCTET STRING - : 00 00 - : } -- This denotes a Null tag and are the last - -- two bytes in INPUT. - - Create a new buffer with the content of that octet string. INPUT - is the orginal buffer with a length as stored at LENGTH. Returns - NULL on error or a new malloced buffer with the length of this new - buffer stored at LENGTH and the number of bytes parsed from input - are added to the value stored at INPUT_CONSUMED. INPUT_CONSUMED is - allowed to be passed as NULL if the caller is not interested in - this value. */ -static unsigned char * -cram_octet_string (const unsigned char *input, size_t *length, - size_t *input_consumed) -{ - const unsigned char *s = input; - size_t n = *length; - unsigned char *output, *d; - struct tag_info ti; - - /* Allocate output buf. We know that it won't be longer than the - input buffer. */ - d = output = gcry_malloc (n); - if (!output) - goto bailout; - - for (;;) - { - if (parse_tag (&s, &n, &ti)) - goto bailout; - if (ti.class == UNIVERSAL && ti.tag == TAG_OCTET_STRING - && !ti.ndef && !ti.is_constructed) - { - memcpy (d, s, ti.length); - s += ti.length; - d += ti.length; - n -= ti.length; - } - else if (ti.class == UNIVERSAL && !ti.tag && !ti.is_constructed) - break; /* Ready */ - else - goto bailout; - } - - - *length = d - output; - if (input_consumed) - *input_consumed += s - input; - return output; - - bailout: - if (input_consumed) - *input_consumed += s - input; - gcry_free (output); - return NULL; -} - - - -static int -string_to_key (int id, char *salt, size_t saltlen, int iter, const char *pw, - int req_keylen, unsigned char *keybuf) -{ - int rc, i, j; - gcry_md_hd_t md; - gcry_mpi_t num_b1 = NULL; - int pwlen; - unsigned char hash[20], buf_b[64], buf_i[128], *p; - size_t cur_keylen; - size_t n; - - cur_keylen = 0; - pwlen = strlen (pw); - if (pwlen > 63/2) - { - log_error ("password too long\n"); - return -1; - } - - if (saltlen < 8) - { - log_error ("salt too short\n"); - return -1; - } - - /* Store salt and password in BUF_I */ - p = buf_i; - for(i=0; i < 64; i++) - *p++ = salt [i%saltlen]; - for(i=j=0; i < 64; i += 2) - { - *p++ = 0; - *p++ = pw[j]; - if (++j > pwlen) /* Note, that we include the trailing zero */ - j = 0; - } - - for (;;) - { - rc = gcry_md_open (&md, GCRY_MD_SHA1, 0); - if (rc) - { - log_error ( "gcry_md_open failed: %s\n", gpg_strerror (rc)); - return rc; - } - for(i=0; i < 64; i++) - gcry_md_putc (md, id); - gcry_md_write (md, buf_i, 128); - memcpy (hash, gcry_md_read (md, 0), 20); - gcry_md_close (md); - for (i=1; i < iter; i++) - gcry_md_hash_buffer (GCRY_MD_SHA1, hash, hash, 20); - - for (i=0; i < 20 && cur_keylen < req_keylen; i++) - keybuf[cur_keylen++] = hash[i]; - if (cur_keylen == req_keylen) - { - gcry_mpi_release (num_b1); - return 0; /* ready */ - } - - /* need more bytes. */ - for(i=0; i < 64; i++) - buf_b[i] = hash[i % 20]; - rc = gcry_mpi_scan (&num_b1, GCRYMPI_FMT_USG, buf_b, 64, &n); - if (rc) - { - log_error ( "gcry_mpi_scan failed: %s\n", gpg_strerror (rc)); - return -1; - } - gcry_mpi_add_ui (num_b1, num_b1, 1); - for (i=0; i < 128; i += 64) - { - gcry_mpi_t num_ij; - - rc = gcry_mpi_scan (&num_ij, GCRYMPI_FMT_USG, buf_i + i, 64, &n); - if (rc) - { - log_error ( "gcry_mpi_scan failed: %s\n", - gpg_strerror (rc)); - return -1; - } - gcry_mpi_add (num_ij, num_ij, num_b1); - gcry_mpi_clear_highbit (num_ij, 64*8); - rc = gcry_mpi_print (GCRYMPI_FMT_USG, buf_i + i, 64, &n, num_ij); - if (rc) - { - log_error ( "gcry_mpi_print failed: %s\n", - gpg_strerror (rc)); - return -1; - } - gcry_mpi_release (num_ij); - } - } -} - - -static int -set_key_iv (gcry_cipher_hd_t chd, char *salt, size_t saltlen, int iter, - const char *pw, int keybytes) -{ - unsigned char keybuf[24]; - int rc; - - assert (keybytes == 5 || keybytes == 24); - if (string_to_key (1, salt, saltlen, iter, pw, keybytes, keybuf)) - return -1; - rc = gcry_cipher_setkey (chd, keybuf, keybytes); - if (rc) - { - log_error ( "gcry_cipher_setkey failed: %s\n", gpg_strerror (rc)); - return -1; - } - - if (string_to_key (2, salt, saltlen, iter, pw, 8, keybuf)) - return -1; - rc = gcry_cipher_setiv (chd, keybuf, 8); - if (rc) - { - log_error ("gcry_cipher_setiv failed: %s\n", gpg_strerror (rc)); - return -1; - } - return 0; -} - - -static void -crypt_block (unsigned char *buffer, size_t length, char *salt, size_t saltlen, - int iter, const char *pw, int cipher_algo, int encrypt) -{ - gcry_cipher_hd_t chd; - int rc; - - rc = gcry_cipher_open (&chd, cipher_algo, GCRY_CIPHER_MODE_CBC, 0); - if (rc) - { - log_error ( "gcry_cipher_open failed: %s\n", gpg_strerror(rc)); - wipememory (buffer, length); - return; - } - if (set_key_iv (chd, salt, saltlen, iter, pw, - cipher_algo == GCRY_CIPHER_RFC2268_40? 5:24)) - { - wipememory (buffer, length); - goto leave; - } - - rc = encrypt? gcry_cipher_encrypt (chd, buffer, length, NULL, 0) - : gcry_cipher_decrypt (chd, buffer, length, NULL, 0); - - if (rc) - { - wipememory (buffer, length); - log_error ( "en/de-crytion failed: %s\n", gpg_strerror (rc)); - goto leave; - } - - leave: - gcry_cipher_close (chd); -} - - -/* Decrypt a block of data and try several encodings of the key. - CIPHERTEXT is the encrypted data of size LENGTH bytes; PLAINTEXT is - a buffer of the same size to receive the decryption result. SALT, - SALTLEN, ITER and PW are the information required for decryption - and CIPHER_ALGO is the algorithm id to use. CHECK_FNC is a - function called with the plaintext and used to check whether the - decryption succeeded; i.e. that a correct passphrase has been - given. That function shall return true if the decryption has likely - succeeded. */ -static void -decrypt_block (const void *ciphertext, unsigned char *plaintext, size_t length, - char *salt, size_t saltlen, - int iter, const char *pw, int cipher_algo, - int (*check_fnc) (const void *, size_t)) -{ - static const char * const charsets[] = { - "", /* No conversion - use the UTF-8 passphrase direct. */ - "ISO-8859-1", - "ISO-8859-15", - "ISO-8859-2", - "ISO-8859-3", - "ISO-8859-4", - "ISO-8859-5", - "ISO-8859-6", - "ISO-8859-7", - "ISO-8859-8", - "ISO-8859-9", - "KOI8-R", - "IBM437", - "IBM850", - "EUC-JP", - "BIG5", - NULL - }; - int charsetidx = 0; - char *convertedpw = NULL; /* Malloced and converted password or NULL. */ - size_t convertedpwsize = 0; /* Allocated length. */ - - for (charsetidx=0; charsets[charsetidx]; charsetidx++) - { - if (*charsets[charsetidx]) - { - jnlib_iconv_t cd; - const char *inptr; - char *outptr; - size_t inbytes, outbytes; - - if (!convertedpw) - { - /* We assume one byte encodings. Thus we can allocate - the buffer of the same size as the original - passphrase; the result will actually be shorter - then. */ - convertedpwsize = strlen (pw) + 1; - convertedpw = gcry_malloc_secure (convertedpwsize); - if (!convertedpw) - { - log_info ("out of secure memory while" - " converting passphrase\n"); - break; /* Give up. */ - } - } - - cd = jnlib_iconv_open (charsets[charsetidx], "utf-8"); - if (cd == (jnlib_iconv_t)(-1)) - continue; - - inptr = pw; - inbytes = strlen (pw); - outptr = convertedpw; - outbytes = convertedpwsize - 1; - if ( jnlib_iconv (cd, (const char **)&inptr, &inbytes, - &outptr, &outbytes) == (size_t)-1) - { - jnlib_iconv_close (cd); - continue; - } - *outptr = 0; - jnlib_iconv_close (cd); - log_info ("decryption failed; trying charset `%s'\n", - charsets[charsetidx]); - } - memcpy (plaintext, ciphertext, length); - crypt_block (plaintext, length, salt, saltlen, iter, - convertedpw? convertedpw:pw, cipher_algo, 0); - if (check_fnc (plaintext, length)) - break; /* Decryption succeeded. */ - } - gcry_free (convertedpw); -} - - -/* Return true if the decryption of an bag_encrypted_data object has - likely succeeded. */ -static int -bag_decrypted_data_p (const void *plaintext, size_t length) -{ - struct tag_info ti; - const unsigned char *p = plaintext; - size_t n = length; - - /* { */ - /* # warning debug code is enabled */ - /* FILE *fp = fopen ("tmp-rc2-plain.der", "wb"); */ - /* if (!fp || fwrite (p, n, 1, fp) != 1) */ - /* exit (2); */ - /* fclose (fp); */ - /* } */ - - if (parse_tag (&p, &n, &ti)) - return 0; - if (ti.class || ti.tag != TAG_SEQUENCE) - return 0; - if (parse_tag (&p, &n, &ti)) - return 0; - - return 1; -} - -/* Note: If R_RESULT is passed as NULL, a key object as already be - processed and thus we need to skip it here. */ -static int -parse_bag_encrypted_data (const unsigned char *buffer, size_t length, - int startoffset, size_t *r_consumed, const char *pw, - void (*certcb)(void*, const unsigned char*, size_t), - void *certcbarg, gcry_mpi_t **r_result) -{ - struct tag_info ti; - const unsigned char *p = buffer; - const unsigned char *p_start = buffer; - size_t n = length; - const char *where; - char salt[20]; - size_t saltlen; - unsigned int iter; - unsigned char *plain = NULL; - int bad_pass = 0; - unsigned char *cram_buffer = NULL; - size_t consumed = 0; /* Number of bytes consumed from the orginal buffer. */ - int is_3des = 0; - gcry_mpi_t *result = NULL; - int result_count; - - if (r_result) - *r_result = NULL; - where = "start"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class != ASNCONTEXT || ti.tag) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.tag != TAG_SEQUENCE) - goto bailout; - - where = "bag.encryptedData.version"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.tag != TAG_INTEGER || ti.length != 1 || *p != 0) - goto bailout; - p++; n--; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.tag != TAG_SEQUENCE) - goto bailout; - - where = "bag.encryptedData.data"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.tag != TAG_OBJECT_ID || ti.length != DIM(oid_data) - || memcmp (p, oid_data, DIM(oid_data))) - goto bailout; - p += DIM(oid_data); - n -= DIM(oid_data); - - where = "bag.encryptedData.keyinfo"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (!ti.class && ti.tag == TAG_OBJECT_ID - && ti.length == DIM(oid_pbeWithSHAAnd40BitRC2_CBC) - && !memcmp (p, oid_pbeWithSHAAnd40BitRC2_CBC, - DIM(oid_pbeWithSHAAnd40BitRC2_CBC))) - { - p += DIM(oid_pbeWithSHAAnd40BitRC2_CBC); - n -= DIM(oid_pbeWithSHAAnd40BitRC2_CBC); - } - else if (!ti.class && ti.tag == TAG_OBJECT_ID - && ti.length == DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC) - && !memcmp (p, oid_pbeWithSHAAnd3_KeyTripleDES_CBC, - DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC))) - { - p += DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC); - n -= DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC); - is_3des = 1; - } - else - goto bailout; - - where = "rc2or3des-params"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_OCTET_STRING - || ti.length < 8 || ti.length > 20 ) - goto bailout; - saltlen = ti.length; - memcpy (salt, p, saltlen); - p += saltlen; - n -= saltlen; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_INTEGER || !ti.length ) - goto bailout; - for (iter=0; ti.length; ti.length--) - { - iter <<= 8; - iter |= (*p++) & 0xff; - n--; - } - - where = "rc2or3des-ciphertext"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - - consumed = p - p_start; - if (ti.class == ASNCONTEXT && ti.tag == 0 && ti.is_constructed && ti.ndef) - { - /* Mozilla exported certs now come with single byte chunks of - octect strings. (Mozilla Firefox 1.0.4). Arghh. */ - where = "cram-rc2or3des-ciphertext"; - cram_buffer = cram_octet_string ( p, &n, &consumed); - if (!cram_buffer) - goto bailout; - p = p_start = cram_buffer; - if (r_consumed) - *r_consumed = consumed; - r_consumed = NULL; /* Ugly hack to not update that value any further. */ - ti.length = n; - } - else if (ti.class == ASNCONTEXT && ti.tag == 0 && ti.length ) - ; - else - goto bailout; - - log_info ("%lu bytes of %s encrypted text\n",ti.length,is_3des?"3DES":"RC2"); - - plain = gcry_malloc_secure (ti.length); - if (!plain) - { - log_error ("error allocating decryption buffer\n"); - goto bailout; - } - decrypt_block (p, plain, ti.length, salt, saltlen, iter, pw, - is_3des? GCRY_CIPHER_3DES : GCRY_CIPHER_RFC2268_40, - bag_decrypted_data_p); - n = ti.length; - startoffset = 0; - p_start = p = plain; - - where = "outer.outer.seq"; - if (parse_tag (&p, &n, &ti)) - { - bad_pass = 1; - goto bailout; - } - if (ti.class || ti.tag != TAG_SEQUENCE) - { - bad_pass = 1; - goto bailout; - } - - if (parse_tag (&p, &n, &ti)) - { - bad_pass = 1; - goto bailout; - } - - /* Loop over all certificates inside the bag. */ - while (n) - { - int iscrlbag = 0; - int iskeybag = 0; - - where = "certbag.nextcert"; - if (ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - - where = "certbag.objectidentifier"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_OBJECT_ID) - goto bailout; - if ( ti.length == DIM(oid_pkcs_12_CertBag) - && !memcmp (p, oid_pkcs_12_CertBag, DIM(oid_pkcs_12_CertBag))) - { - p += DIM(oid_pkcs_12_CertBag); - n -= DIM(oid_pkcs_12_CertBag); - } - else if ( ti.length == DIM(oid_pkcs_12_CrlBag) - && !memcmp (p, oid_pkcs_12_CrlBag, DIM(oid_pkcs_12_CrlBag))) - { - p += DIM(oid_pkcs_12_CrlBag); - n -= DIM(oid_pkcs_12_CrlBag); - iscrlbag = 1; - } - else if ( ti.length == DIM(oid_pkcs_12_keyBag) - && !memcmp (p, oid_pkcs_12_keyBag, DIM(oid_pkcs_12_keyBag))) - { - /* The TrustedMIME plugin for MS Outlook started to create - files with just one outer 3DES encrypted container and - inside the certificates as well as the key. */ - p += DIM(oid_pkcs_12_keyBag); - n -= DIM(oid_pkcs_12_keyBag); - iskeybag = 1; - } - else - goto bailout; - - where = "certbag.before.certheader"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class != ASNCONTEXT || ti.tag) - goto bailout; - if (iscrlbag) - { - log_info ("skipping unsupported crlBag\n"); - p += ti.length; - n -= ti.length; - } - else if (iskeybag && (result || !r_result)) - { - log_info ("one keyBag already processed; skipping this one\n"); - p += ti.length; - n -= ti.length; - } - else if (iskeybag) - { - int len; - - log_info ("processing simple keyBag\n"); - - /* Fixme: This code is duplicated from parse_bag_data. */ - if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER - || ti.length != 1 || *p) - goto bailout; - p++; n--; - if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - len = ti.length; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (len < ti.nhdr) - goto bailout; - len -= ti.nhdr; - if (ti.class || ti.tag != TAG_OBJECT_ID - || ti.length != DIM(oid_rsaEncryption) - || memcmp (p, oid_rsaEncryption, - DIM(oid_rsaEncryption))) - goto bailout; - p += DIM (oid_rsaEncryption); - n -= DIM (oid_rsaEncryption); - if (len < ti.length) - goto bailout; - len -= ti.length; - if (n < len) - goto bailout; - p += len; - n -= len; - if ( parse_tag (&p, &n, &ti) - || ti.class || ti.tag != TAG_OCTET_STRING) - goto bailout; - if ( parse_tag (&p, &n, &ti) - || ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - len = ti.length; - - result = gcry_calloc (10, sizeof *result); - if (!result) - { - log_error ( "error allocating result array\n"); - goto bailout; - } - result_count = 0; - - where = "reading.keybag.key-parameters"; - for (result_count = 0; len && result_count < 9;) - { - if ( parse_tag (&p, &n, &ti) - || ti.class || ti.tag != TAG_INTEGER) - goto bailout; - if (len < ti.nhdr) - goto bailout; - len -= ti.nhdr; - if (len < ti.length) - goto bailout; - len -= ti.length; - if (!result_count && ti.length == 1 && !*p) - ; /* ignore the very first one if it is a 0 */ - else - { - int rc; - - rc = gcry_mpi_scan (result+result_count, GCRYMPI_FMT_USG, p, - ti.length, NULL); - if (rc) - { - log_error ("error parsing key parameter: %s\n", - gpg_strerror (rc)); - goto bailout; - } - result_count++; - } - p += ti.length; - n -= ti.length; - } - if (len) - goto bailout; - } - else - { - log_info ("processing certBag\n"); - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_OBJECT_ID - || ti.length != DIM(oid_x509Certificate_for_pkcs_12) - || memcmp (p, oid_x509Certificate_for_pkcs_12, - DIM(oid_x509Certificate_for_pkcs_12))) - goto bailout; - p += DIM(oid_x509Certificate_for_pkcs_12); - n -= DIM(oid_x509Certificate_for_pkcs_12); - - where = "certbag.before.octetstring"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class != ASNCONTEXT || ti.tag) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_OCTET_STRING || ti.ndef) - goto bailout; - - /* Return the certificate. */ - if (certcb) - certcb (certcbarg, p, ti.length); - - p += ti.length; - n -= ti.length; - } - - /* Ugly hack to cope with the padding: Forget about the rest if - that is less or equal to the cipher's block length. We can - reasonable assume that all valid data will be longer than - just one block. */ - if (n <= 8) - n = 0; - - /* Skip the optional SET with the pkcs12 cert attributes. */ - if (n) - { - where = "bag.attributes"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (!ti.class && ti.tag == TAG_SEQUENCE) - ; /* No attributes. */ - else if (!ti.class && ti.tag == TAG_SET && !ti.ndef) - { /* The optional SET. */ - p += ti.length; - n -= ti.length; - if (n <= 8) - n = 0; - if (n && parse_tag (&p, &n, &ti)) - goto bailout; - } - else - goto bailout; - } - } - - if (r_consumed) - *r_consumed = consumed; - gcry_free (plain); - gcry_free (cram_buffer); - if (r_result) - *r_result = result; - return 0; - - bailout: - if (result) - { - int i; - - for (i=0; result[i]; i++) - gcry_mpi_release (result[i]); - gcry_free (result); - } - if (r_consumed) - *r_consumed = consumed; - gcry_free (plain); - gcry_free (cram_buffer); - log_error ("encryptedData error at \"%s\", offset %u\n", - where, (unsigned int)((p - p_start)+startoffset)); - if (bad_pass) - { - /* Note, that the following string might be used by other programs - to check for a bad passphrase; it should therefore not be - translated or changed. */ - log_error ("possibly bad passphrase given\n"); - } - return -1; -} - - -/* Return true if the decryption of a bag_data object has likely - succeeded. */ -static int -bag_data_p (const void *plaintext, size_t length) -{ - struct tag_info ti; - const unsigned char *p = plaintext; - size_t n = length; - -/* { */ -/* # warning debug code is enabled */ -/* FILE *fp = fopen ("tmp-3des-plain-key.der", "wb"); */ -/* if (!fp || fwrite (p, n, 1, fp) != 1) */ -/* exit (2); */ -/* fclose (fp); */ -/* } */ - - if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE) - return 0; - if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER - || ti.length != 1 || *p) - return 0; - - return 1; -} - - -static gcry_mpi_t * -parse_bag_data (const unsigned char *buffer, size_t length, int startoffset, - size_t *r_consumed, const char *pw) -{ - int rc; - struct tag_info ti; - const unsigned char *p = buffer; - const unsigned char *p_start = buffer; - size_t n = length; - const char *where; - char salt[20]; - size_t saltlen; - unsigned int iter; - int len; - unsigned char *plain = NULL; - gcry_mpi_t *result = NULL; - int result_count, i; - unsigned char *cram_buffer = NULL; - size_t consumed = 0; /* Number of bytes consumed from the orginal buffer. */ - - where = "start"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class != ASNCONTEXT || ti.tag) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_OCTET_STRING) - goto bailout; - - consumed = p - p_start; - if (ti.is_constructed && ti.ndef) - { - /* Mozilla exported certs now come with single byte chunks of - octect strings. (Mozilla Firefox 1.0.4). Arghh. */ - where = "cram-data.outersegs"; - cram_buffer = cram_octet_string ( p, &n, &consumed); - if (!cram_buffer) - goto bailout; - p = p_start = cram_buffer; - if (r_consumed) - *r_consumed = consumed; - r_consumed = NULL; /* Ugly hack to not update that value any further. */ - } - - - where = "data.outerseqs"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - - where = "data.objectidentifier"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_OBJECT_ID - || ti.length != DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag) - || memcmp (p, oid_pkcs_12_pkcs_8ShroudedKeyBag, - DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag))) - goto bailout; - p += DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag); - n -= DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag); - - where = "shrouded,outerseqs"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class != ASNCONTEXT || ti.tag) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_OBJECT_ID - || ti.length != DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC) - || memcmp (p, oid_pbeWithSHAAnd3_KeyTripleDES_CBC, - DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC))) - goto bailout; - p += DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC); - n -= DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC); - - where = "3des-params"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_OCTET_STRING - || ti.length < 8 || ti.length > 20) - goto bailout; - saltlen = ti.length; - memcpy (salt, p, saltlen); - p += saltlen; - n -= saltlen; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_INTEGER || !ti.length ) - goto bailout; - for (iter=0; ti.length; ti.length--) - { - iter <<= 8; - iter |= (*p++) & 0xff; - n--; - } - - where = "3des-ciphertext"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_OCTET_STRING || !ti.length ) - goto bailout; - - log_info ("%lu bytes of 3DES encrypted text\n", ti.length); - - plain = gcry_malloc_secure (ti.length); - if (!plain) - { - log_error ("error allocating decryption buffer\n"); - goto bailout; - } - consumed += p - p_start + ti.length; - decrypt_block (p, plain, ti.length, salt, saltlen, iter, pw, - GCRY_CIPHER_3DES, - bag_data_p); - n = ti.length; - startoffset = 0; - p_start = p = plain; - - where = "decrypted-text"; - if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER - || ti.length != 1 || *p) - goto bailout; - p++; n--; - if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - len = ti.length; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (len < ti.nhdr) - goto bailout; - len -= ti.nhdr; - if (ti.class || ti.tag != TAG_OBJECT_ID - || ti.length != DIM(oid_rsaEncryption) - || memcmp (p, oid_rsaEncryption, - DIM(oid_rsaEncryption))) - goto bailout; - p += DIM (oid_rsaEncryption); - n -= DIM (oid_rsaEncryption); - if (len < ti.length) - goto bailout; - len -= ti.length; - if (n < len) - goto bailout; - p += len; - n -= len; - if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_OCTET_STRING) - goto bailout; - if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - len = ti.length; - - result = gcry_calloc (10, sizeof *result); - if (!result) - { - log_error ( "error allocating result array\n"); - goto bailout; - } - result_count = 0; - - where = "reading.key-parameters"; - for (result_count=0; len && result_count < 9;) - { - if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER) - goto bailout; - if (len < ti.nhdr) - goto bailout; - len -= ti.nhdr; - if (len < ti.length) - goto bailout; - len -= ti.length; - if (!result_count && ti.length == 1 && !*p) - ; /* ignore the very first one if it is a 0 */ - else - { - rc = gcry_mpi_scan (result+result_count, GCRYMPI_FMT_USG, p, - ti.length, NULL); - if (rc) - { - log_error ("error parsing key parameter: %s\n", - gpg_strerror (rc)); - goto bailout; - } - result_count++; - } - p += ti.length; - n -= ti.length; - } - if (len) - goto bailout; - - gcry_free (cram_buffer); - if (r_consumed) - *r_consumed = consumed; - return result; - - bailout: - gcry_free (plain); - if (result) - { - for (i=0; result[i]; i++) - gcry_mpi_release (result[i]); - gcry_free (result); - } - gcry_free (cram_buffer); - log_error ( "data error at \"%s\", offset %u\n", - where, (unsigned int)((p - buffer) + startoffset)); - if (r_consumed) - *r_consumed = consumed; - return NULL; -} - - -/* Parse a PKCS12 object and return an array of MPI representing the - secret key parameters. This is a very limited implementation in - that it is only able to look for 3DES encoded encryptedData and - tries to extract the first private key object it finds. In case of - an error NULL is returned. CERTCB and CERRTCBARG are used to pass - X.509 certificates back to the caller. */ -gcry_mpi_t * -p12_parse (const unsigned char *buffer, size_t length, const char *pw, - void (*certcb)(void*, const unsigned char*, size_t), - void *certcbarg) -{ - struct tag_info ti; - const unsigned char *p = buffer; - const unsigned char *p_start = buffer; - size_t n = length; - const char *where; - int bagseqlength, len; - int bagseqndef, lenndef; - gcry_mpi_t *result = NULL; - unsigned char *cram_buffer = NULL; - - where = "pfx"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.tag != TAG_SEQUENCE) - goto bailout; - - where = "pfxVersion"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.tag != TAG_INTEGER || ti.length != 1 || *p != 3) - goto bailout; - p++; n--; - - where = "authSave"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.tag != TAG_SEQUENCE) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.tag != TAG_OBJECT_ID || ti.length != DIM(oid_data) - || memcmp (p, oid_data, DIM(oid_data))) - goto bailout; - p += DIM(oid_data); - n -= DIM(oid_data); - - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class != ASNCONTEXT || ti.tag) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class != UNIVERSAL || ti.tag != TAG_OCTET_STRING) - goto bailout; - - if (ti.is_constructed && ti.ndef) - { - /* Mozilla exported certs now come with single byte chunks of - octect strings. (Mozilla Firefox 1.0.4). Arghh. */ - where = "cram-bags"; - cram_buffer = cram_octet_string ( p, &n, NULL); - if (!cram_buffer) - goto bailout; - p = p_start = cram_buffer; - } - - where = "bags"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class != UNIVERSAL || ti.tag != TAG_SEQUENCE) - goto bailout; - bagseqndef = ti.ndef; - bagseqlength = ti.length; - while (bagseqlength || bagseqndef) - { -/* log_debug ( "at offset %u\n", (p - p_start)); */ - where = "bag-sequence"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (bagseqndef && ti.class == UNIVERSAL && !ti.tag && !ti.is_constructed) - break; /* Ready */ - if (ti.class != UNIVERSAL || ti.tag != TAG_SEQUENCE) - goto bailout; - - if (!bagseqndef) - { - if (bagseqlength < ti.nhdr) - goto bailout; - bagseqlength -= ti.nhdr; - if (bagseqlength < ti.length) - goto bailout; - bagseqlength -= ti.length; - } - lenndef = ti.ndef; - len = ti.length; - - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (lenndef) - len = ti.nhdr; - else - len -= ti.nhdr; - - if (ti.tag == TAG_OBJECT_ID && ti.length == DIM(oid_encryptedData) - && !memcmp (p, oid_encryptedData, DIM(oid_encryptedData))) - { - size_t consumed = 0; - - p += DIM(oid_encryptedData); - n -= DIM(oid_encryptedData); - if (!lenndef) - len -= DIM(oid_encryptedData); - where = "bag.encryptedData"; - if (parse_bag_encrypted_data (p, n, (p - p_start), &consumed, pw, - certcb, certcbarg, - result? NULL : &result)) - goto bailout; - if (lenndef) - len += consumed; - } - else if (ti.tag == TAG_OBJECT_ID && ti.length == DIM(oid_data) - && !memcmp (p, oid_data, DIM(oid_data))) - { - if (result) - { - log_info ("already got an key object, skipping this one\n"); - p += ti.length; - n -= ti.length; - } - else - { - size_t consumed = 0; - - p += DIM(oid_data); - n -= DIM(oid_data); - if (!lenndef) - len -= DIM(oid_data); - result = parse_bag_data (p, n, (p - p_start), &consumed, pw); - if (!result) - goto bailout; - if (lenndef) - len += consumed; - } - } - else - { - log_info ("unknown bag type - skipped\n"); - p += ti.length; - n -= ti.length; - } - - if (len < 0 || len > n) - goto bailout; - p += len; - n -= len; - if (lenndef) - { - /* Need to skip the Null Tag. */ - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (!(ti.class == UNIVERSAL && !ti.tag && !ti.is_constructed)) - goto bailout; - } - } - - gcry_free (cram_buffer); - return result; - bailout: - log_error ("error at \"%s\", offset %u\n", - where, (unsigned int)(p - p_start)); - if (result) - { - int i; - - for (i=0; result[i]; i++) - gcry_mpi_release (result[i]); - gcry_free (result); - } - gcry_free (cram_buffer); - return NULL; -} - - - -static size_t -compute_tag_length (size_t n) -{ - int needed = 0; - - if (n < 128) - needed += 2; /* tag and one length byte */ - else if (n < 256) - needed += 3; /* tag, number of length bytes, 1 length byte */ - else if (n < 65536) - needed += 4; /* tag, number of length bytes, 2 length bytes */ - else - { - log_error ("object too larger to encode\n"); - return 0; - } - return needed; -} - -static unsigned char * -store_tag_length (unsigned char *p, int tag, size_t n) -{ - if (tag == TAG_SEQUENCE) - tag |= 0x20; /* constructed */ - - *p++ = tag; - if (n < 128) - *p++ = n; - else if (n < 256) - { - *p++ = 0x81; - *p++ = n; - } - else if (n < 65536) - { - *p++ = 0x82; - *p++ = n >> 8; - *p++ = n; - } - - return p; -} - - -/* Create the final PKCS-12 object from the sequences contained in - SEQLIST. PW is the password. That array is terminated with an NULL - object. */ -static unsigned char * -create_final (struct buffer_s *sequences, const char *pw, size_t *r_length) -{ - int i; - size_t needed = 0; - size_t len[8], n; - unsigned char *macstart; - size_t maclen; - unsigned char *result, *p; - size_t resultlen; - char salt[8]; - unsigned char keybuf[20]; - gcry_md_hd_t md; - int rc; - int with_mac = 1; - - - /* 9 steps to create the pkcs#12 Krampf. */ - - /* 8. The MAC. */ - /* We add this at step 0. */ - - /* 7. All the buffers. */ - for (i=0; sequences[i].buffer; i++) - needed += sequences[i].length; - - /* 6. This goes into a sequences. */ - len[6] = needed; - n = compute_tag_length (needed); - needed += n; - - /* 5. Encapsulate all in an octet string. */ - len[5] = needed; - n = compute_tag_length (needed); - needed += n; - - /* 4. And tag it with [0]. */ - len[4] = needed; - n = compute_tag_length (needed); - needed += n; - - /* 3. Prepend an data OID. */ - needed += 2 + DIM (oid_data); - - /* 2. Put all into a sequences. */ - len[2] = needed; - n = compute_tag_length (needed); - needed += n; - - /* 1. Prepend the version integer 3. */ - needed += 3; - - /* 0. And the final outer sequence. */ - if (with_mac) - needed += DIM (data_mactemplate); - len[0] = needed; - n = compute_tag_length (needed); - needed += n; - - /* Allocate a buffer. */ - result = gcry_malloc (needed); - if (!result) - { - log_error ("error allocating buffer\n"); - return NULL; - } - p = result; - - /* 0. Store the very outer sequence. */ - p = store_tag_length (p, TAG_SEQUENCE, len[0]); - - /* 1. Store the version integer 3. */ - *p++ = TAG_INTEGER; - *p++ = 1; - *p++ = 3; - - /* 2. Store another sequence. */ - p = store_tag_length (p, TAG_SEQUENCE, len[2]); - - /* 3. Store the data OID. */ - p = store_tag_length (p, TAG_OBJECT_ID, DIM (oid_data)); - memcpy (p, oid_data, DIM (oid_data)); - p += DIM (oid_data); - - /* 4. Next comes a context tag. */ - p = store_tag_length (p, 0xa0, len[4]); - - /* 5. And an octet string. */ - p = store_tag_length (p, TAG_OCTET_STRING, len[5]); - - /* 6. And the inner sequence. */ - macstart = p; - p = store_tag_length (p, TAG_SEQUENCE, len[6]); - - /* 7. Append all the buffers. */ - for (i=0; sequences[i].buffer; i++) - { - memcpy (p, sequences[i].buffer, sequences[i].length); - p += sequences[i].length; - } - - if (with_mac) - { - /* Intermezzo to compute the MAC. */ - maclen = p - macstart; - gcry_randomize (salt, 8, GCRY_STRONG_RANDOM); - if (string_to_key (3, salt, 8, 2048, pw, 20, keybuf)) - { - gcry_free (result); - return NULL; - } - rc = gcry_md_open (&md, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC); - if (rc) - { - log_error ("gcry_md_open failed: %s\n", gpg_strerror (rc)); - gcry_free (result); - return NULL; - } - rc = gcry_md_setkey (md, keybuf, 20); - if (rc) - { - log_error ("gcry_md_setkey failed: %s\n", gpg_strerror (rc)); - gcry_md_close (md); - gcry_free (result); - return NULL; - } - gcry_md_write (md, macstart, maclen); - - /* 8. Append the MAC template and fix it up. */ - memcpy (p, data_mactemplate, DIM (data_mactemplate)); - memcpy (p + DATA_MACTEMPLATE_SALT_OFF, salt, 8); - memcpy (p + DATA_MACTEMPLATE_MAC_OFF, gcry_md_read (md, 0), 20); - p += DIM (data_mactemplate); - gcry_md_close (md); - } - - /* Ready. */ - resultlen = p - result; - if (needed != resultlen) - log_debug ("length mismatch: %lu, %lu\n", - (unsigned long)needed, (unsigned long)resultlen); - - *r_length = resultlen; - return result; -} - - -/* Build a DER encoded SEQUENCE with the key: - - SEQUENCE { - INTEGER 0 - SEQUENCE { - OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1) - NULL - } - OCTET STRING, encapsulates { - SEQUENCE { - INTEGER 0 - INTEGER - INTEGER - INTEGER - INTEGER - INTEGER - INTEGER - INTEGER - INTEGER - } - } - } -*/ - -static unsigned char * -build_key_sequence (gcry_mpi_t *kparms, size_t *r_length) -{ - int rc, i; - size_t needed, n; - unsigned char *plain, *p; - size_t plainlen; - size_t outseqlen, oidseqlen, octstrlen, inseqlen; - - needed = 3; /* The version(?) integer of value 0. */ - for (i=0; kparms[i]; i++) - { - n = 0; - rc = gcry_mpi_print (GCRYMPI_FMT_STD, NULL, 0, &n, kparms[i]); - if (rc) - { - log_error ("error formatting parameter: %s\n", gpg_strerror (rc)); - return NULL; - } - needed += n; - n = compute_tag_length (n); - if (!n) - return NULL; - needed += n; - } - if (i != 8) - { - log_error ("invalid parameters for p12_build\n"); - return NULL; - } - /* Now this all goes into a sequence. */ - inseqlen = needed; - n = compute_tag_length (needed); - if (!n) - return NULL; - needed += n; - /* Encapsulate all into an octet string. */ - octstrlen = needed; - n = compute_tag_length (needed); - if (!n) - return NULL; - needed += n; - /* Prepend the object identifier sequence. */ - oidseqlen = 2 + DIM (oid_rsaEncryption) + 2; - needed += 2 + oidseqlen; - /* The version number. */ - needed += 3; - /* And finally put the whole thing into a sequence. */ - outseqlen = needed; - n = compute_tag_length (needed); - if (!n) - return NULL; - needed += n; - - /* allocate 8 extra bytes for padding */ - plain = gcry_malloc_secure (needed+8); - if (!plain) - { - log_error ("error allocating encryption buffer\n"); - return NULL; - } - - /* And now fill the plaintext buffer. */ - p = plain; - p = store_tag_length (p, TAG_SEQUENCE, outseqlen); - /* Store version. */ - *p++ = TAG_INTEGER; - *p++ = 1; - *p++ = 0; - /* Store object identifier sequence. */ - p = store_tag_length (p, TAG_SEQUENCE, oidseqlen); - p = store_tag_length (p, TAG_OBJECT_ID, DIM (oid_rsaEncryption)); - memcpy (p, oid_rsaEncryption, DIM (oid_rsaEncryption)); - p += DIM (oid_rsaEncryption); - *p++ = TAG_NULL; - *p++ = 0; - /* Start with the octet string. */ - p = store_tag_length (p, TAG_OCTET_STRING, octstrlen); - p = store_tag_length (p, TAG_SEQUENCE, inseqlen); - /* Store the key parameters. */ - *p++ = TAG_INTEGER; - *p++ = 1; - *p++ = 0; - for (i=0; kparms[i]; i++) - { - n = 0; - rc = gcry_mpi_print (GCRYMPI_FMT_STD, NULL, 0, &n, kparms[i]); - if (rc) - { - log_error ("oops: error formatting parameter: %s\n", - gpg_strerror (rc)); - gcry_free (plain); - return NULL; - } - p = store_tag_length (p, TAG_INTEGER, n); - - n = plain + needed - p; - rc = gcry_mpi_print (GCRYMPI_FMT_STD, p, n, &n, kparms[i]); - if (rc) - { - log_error ("oops: error storing parameter: %s\n", - gpg_strerror (rc)); - gcry_free (plain); - return NULL; - } - p += n; - } - - plainlen = p - plain; - assert (needed == plainlen); - /* Append some pad characters; we already allocated extra space. */ - n = 8 - plainlen % 8; - for (i=0; i < n; i++, plainlen++) - *p++ = n; - - *r_length = plainlen; - return plain; -} - - - -static unsigned char * -build_key_bag (unsigned char *buffer, size_t buflen, char *salt, - const unsigned char *sha1hash, const char *keyidstr, - size_t *r_length) -{ - size_t len[11], needed; - unsigned char *p, *keybag; - size_t keybaglen; - - /* Walk 11 steps down to collect the info: */ - - /* 10. The data goes into an octet string. */ - needed = compute_tag_length (buflen); - needed += buflen; - - /* 9. Prepend the algorithm identifier. */ - needed += DIM (data_3desiter2048); - - /* 8. Put a sequence around. */ - len[8] = needed; - needed += compute_tag_length (needed); - - /* 7. Prepend a [0] tag. */ - len[7] = needed; - needed += compute_tag_length (needed); - - /* 6b. The attributes which are appended at the end. */ - if (sha1hash) - needed += DIM (data_attrtemplate) + 20; - - /* 6. Prepend the shroudedKeyBag OID. */ - needed += 2 + DIM (oid_pkcs_12_pkcs_8ShroudedKeyBag); - - /* 5+4. Put all into two sequences. */ - len[5] = needed; - needed += compute_tag_length ( needed); - len[4] = needed; - needed += compute_tag_length (needed); - - /* 3. This all goes into an octet string. */ - len[3] = needed; - needed += compute_tag_length (needed); - - /* 2. Prepend another [0] tag. */ - len[2] = needed; - needed += compute_tag_length (needed); - - /* 1. Prepend the data OID. */ - needed += 2 + DIM (oid_data); - - /* 0. Prepend another sequence. */ - len[0] = needed; - needed += compute_tag_length (needed); - - /* Now that we have all length information, allocate a buffer. */ - p = keybag = gcry_malloc (needed); - if (!keybag) - { - log_error ("error allocating buffer\n"); - return NULL; - } - - /* Walk 11 steps up to store the data. */ - - /* 0. Store the first sequence. */ - p = store_tag_length (p, TAG_SEQUENCE, len[0]); - - /* 1. Store the data OID. */ - p = store_tag_length (p, TAG_OBJECT_ID, DIM (oid_data)); - memcpy (p, oid_data, DIM (oid_data)); - p += DIM (oid_data); - - /* 2. Store a [0] tag. */ - p = store_tag_length (p, 0xa0, len[2]); - - /* 3. And an octet string. */ - p = store_tag_length (p, TAG_OCTET_STRING, len[3]); - - /* 4+5. Two sequences. */ - p = store_tag_length (p, TAG_SEQUENCE, len[4]); - p = store_tag_length (p, TAG_SEQUENCE, len[5]); - - /* 6. Store the shroudedKeyBag OID. */ - p = store_tag_length (p, TAG_OBJECT_ID, - DIM (oid_pkcs_12_pkcs_8ShroudedKeyBag)); - memcpy (p, oid_pkcs_12_pkcs_8ShroudedKeyBag, - DIM (oid_pkcs_12_pkcs_8ShroudedKeyBag)); - p += DIM (oid_pkcs_12_pkcs_8ShroudedKeyBag); - - /* 7. Store a [0] tag. */ - p = store_tag_length (p, 0xa0, len[7]); - - /* 8. Store a sequence. */ - p = store_tag_length (p, TAG_SEQUENCE, len[8]); - - /* 9. Now for the pre-encoded algorithm identifier and the salt. */ - memcpy (p, data_3desiter2048, DIM (data_3desiter2048)); - memcpy (p + DATA_3DESITER2048_SALT_OFF, salt, 8); - p += DIM (data_3desiter2048); - - /* 10. And the octet string with the encrypted data. */ - p = store_tag_length (p, TAG_OCTET_STRING, buflen); - memcpy (p, buffer, buflen); - p += buflen; - - /* Append the attributes whose length we calculated at step 2b. */ - if (sha1hash) - { - int i; - - memcpy (p, data_attrtemplate, DIM (data_attrtemplate)); - for (i=0; i < 8; i++) - p[DATA_ATTRTEMPLATE_KEYID_OFF+2*i+1] = keyidstr[i]; - p += DIM (data_attrtemplate); - memcpy (p, sha1hash, 20); - p += 20; - } - - - keybaglen = p - keybag; - if (needed != keybaglen) - log_debug ("length mismatch: %lu, %lu\n", - (unsigned long)needed, (unsigned long)keybaglen); - - *r_length = keybaglen; - return keybag; -} - - -static unsigned char * -build_cert_bag (unsigned char *buffer, size_t buflen, char *salt, - size_t *r_length) -{ - size_t len[9], needed; - unsigned char *p, *certbag; - size_t certbaglen; - - /* Walk 9 steps down to collect the info: */ - - /* 8. The data goes into an octet string. */ - needed = compute_tag_length (buflen); - needed += buflen; - - /* 7. The algorithm identifier. */ - needed += DIM (data_rc2iter2048); - - /* 6. The data OID. */ - needed += 2 + DIM (oid_data); - - /* 5. A sequence. */ - len[5] = needed; - needed += compute_tag_length ( needed); - - /* 4. An integer. */ - needed += 3; - - /* 3. A sequence. */ - len[3] = needed; - needed += compute_tag_length (needed); - - /* 2. A [0] tag. */ - len[2] = needed; - needed += compute_tag_length (needed); - - /* 1. The encryptedData OID. */ - needed += 2 + DIM (oid_encryptedData); - - /* 0. The first sequence. */ - len[0] = needed; - needed += compute_tag_length (needed); - - /* Now that we have all length information, allocate a buffer. */ - p = certbag = gcry_malloc (needed); - if (!certbag) - { - log_error ("error allocating buffer\n"); - return NULL; - } - - /* Walk 9 steps up to store the data. */ - - /* 0. Store the first sequence. */ - p = store_tag_length (p, TAG_SEQUENCE, len[0]); - - /* 1. Store the encryptedData OID. */ - p = store_tag_length (p, TAG_OBJECT_ID, DIM (oid_encryptedData)); - memcpy (p, oid_encryptedData, DIM (oid_encryptedData)); - p += DIM (oid_encryptedData); - - /* 2. Store a [0] tag. */ - p = store_tag_length (p, 0xa0, len[2]); - - /* 3. Store a sequence. */ - p = store_tag_length (p, TAG_SEQUENCE, len[3]); - - /* 4. Store the integer 0. */ - *p++ = TAG_INTEGER; - *p++ = 1; - *p++ = 0; - - /* 5. Store a sequence. */ - p = store_tag_length (p, TAG_SEQUENCE, len[5]); - - /* 6. Store the data OID. */ - p = store_tag_length (p, TAG_OBJECT_ID, DIM (oid_data)); - memcpy (p, oid_data, DIM (oid_data)); - p += DIM (oid_data); - - /* 7. Now for the pre-encoded algorithm identifier and the salt. */ - memcpy (p, data_rc2iter2048, DIM (data_rc2iter2048)); - memcpy (p + DATA_RC2ITER2048_SALT_OFF, salt, 8); - p += DIM (data_rc2iter2048); - - /* 8. And finally the [0] tag with the encrypted data. */ - p = store_tag_length (p, 0x80, buflen); - memcpy (p, buffer, buflen); - p += buflen; - certbaglen = p - certbag; - - if (needed != certbaglen) - log_debug ("length mismatch: %lu, %lu\n", - (unsigned long)needed, (unsigned long)certbaglen); - - *r_length = certbaglen; - return certbag; -} - - -static unsigned char * -build_cert_sequence (unsigned char *buffer, size_t buflen, - const unsigned char *sha1hash, const char *keyidstr, - size_t *r_length) -{ - size_t len[8], needed, n; - unsigned char *p, *certseq; - size_t certseqlen; - int i; - - assert (strlen (keyidstr) == 8); - - /* Walk 8 steps down to collect the info: */ - - /* 7. The data goes into an octet string. */ - needed = compute_tag_length (buflen); - needed += buflen; - - /* 6. A [0] tag. */ - len[6] = needed; - needed += compute_tag_length (needed); - - /* 5. An OID. */ - needed += 2 + DIM (oid_x509Certificate_for_pkcs_12); - - /* 4. A sequence. */ - len[4] = needed; - needed += compute_tag_length (needed); - - /* 3. A [0] tag. */ - len[3] = needed; - needed += compute_tag_length (needed); - - /* 2b. The attributes which are appended at the end. */ - if (sha1hash) - needed += DIM (data_attrtemplate) + 20; - - /* 2. An OID. */ - needed += 2 + DIM (oid_pkcs_12_CertBag); - - /* 1. A sequence. */ - len[1] = needed; - needed += compute_tag_length (needed); - - /* 0. The first sequence. */ - len[0] = needed; - needed += compute_tag_length (needed); - - /* Now that we have all length information, allocate a buffer. */ - p = certseq = gcry_malloc (needed + 8 /*(for padding)*/); - if (!certseq) - { - log_error ("error allocating buffer\n"); - return NULL; - } - - /* Walk 8 steps up to store the data. */ - - /* 0. Store the first sequence. */ - p = store_tag_length (p, TAG_SEQUENCE, len[0]); - - /* 1. Store the second sequence. */ - p = store_tag_length (p, TAG_SEQUENCE, len[1]); - - /* 2. Store the pkcs12-cert-bag OID. */ - p = store_tag_length (p, TAG_OBJECT_ID, DIM (oid_pkcs_12_CertBag)); - memcpy (p, oid_pkcs_12_CertBag, DIM (oid_pkcs_12_CertBag)); - p += DIM (oid_pkcs_12_CertBag); - - /* 3. Store a [0] tag. */ - p = store_tag_length (p, 0xa0, len[3]); - - /* 4. Store a sequence. */ - p = store_tag_length (p, TAG_SEQUENCE, len[4]); - - /* 5. Store the x509Certificate OID. */ - p = store_tag_length (p, TAG_OBJECT_ID, - DIM (oid_x509Certificate_for_pkcs_12)); - memcpy (p, oid_x509Certificate_for_pkcs_12, - DIM (oid_x509Certificate_for_pkcs_12)); - p += DIM (oid_x509Certificate_for_pkcs_12); - - /* 6. Store a [0] tag. */ - p = store_tag_length (p, 0xa0, len[6]); - - /* 7. And the octet string with the actual certificate. */ - p = store_tag_length (p, TAG_OCTET_STRING, buflen); - memcpy (p, buffer, buflen); - p += buflen; - - /* Append the attributes whose length we calculated at step 2b. */ - if (sha1hash) - { - memcpy (p, data_attrtemplate, DIM (data_attrtemplate)); - for (i=0; i < 8; i++) - p[DATA_ATTRTEMPLATE_KEYID_OFF+2*i+1] = keyidstr[i]; - p += DIM (data_attrtemplate); - memcpy (p, sha1hash, 20); - p += 20; - } - - certseqlen = p - certseq; - if (needed != certseqlen) - log_debug ("length mismatch: %lu, %lu\n", - (unsigned long)needed, (unsigned long)certseqlen); - - /* Append some pad characters; we already allocated extra space. */ - n = 8 - certseqlen % 8; - for (i=0; i < n; i++, certseqlen++) - *p++ = n; - - *r_length = certseqlen; - return certseq; -} - - -/* Expect the RSA key parameters in KPARMS and a password in PW. - Create a PKCS structure from it and return it as well as the length - in R_LENGTH; return NULL in case of an error. If CHARSET is not - NULL, re-encode PW to that character set. */ -unsigned char * -p12_build (gcry_mpi_t *kparms, unsigned char *cert, size_t certlen, - const char *pw, const char *charset, size_t *r_length) -{ - unsigned char *buffer = NULL; - size_t n, buflen; - char salt[8]; - struct buffer_s seqlist[3]; - int seqlistidx = 0; - unsigned char sha1hash[20]; - char keyidstr[8+1]; - char *pwbuf = NULL; - size_t pwbufsize = 0; - - n = buflen = 0; /* (avoid compiler warning). */ - memset (sha1hash, 0, 20); - *keyidstr = 0; - - if (charset && pw && *pw) - { - jnlib_iconv_t cd; - const char *inptr; - char *outptr; - size_t inbytes, outbytes; - - /* We assume that the converted passphrase is at max 2 times - longer than its utf-8 encoding. */ - pwbufsize = strlen (pw)*2 + 1; - pwbuf = gcry_malloc_secure (pwbufsize); - if (!pwbuf) - { - log_error ("out of secure memory while converting passphrase\n"); - goto failure; - } - - cd = jnlib_iconv_open (charset, "utf-8"); - if (cd == (jnlib_iconv_t)(-1)) - { - log_error ("can't convert passphrase to" - " requested charset `%s': %s\n", - charset, strerror (errno)); - gcry_free (pwbuf); - goto failure; - } - - inptr = pw; - inbytes = strlen (pw); - outptr = pwbuf; - outbytes = pwbufsize - 1; - if ( jnlib_iconv (cd, (const char **)&inptr, &inbytes, - &outptr, &outbytes) == (size_t)-1) - { - log_error ("error converting passphrase to" - " requested charset `%s': %s\n", - charset, strerror (errno)); - gcry_free (pwbuf); - jnlib_iconv_close (cd); - goto failure; - } - *outptr = 0; - jnlib_iconv_close (cd); - pw = pwbuf; - } - - - if (cert && certlen) - { - /* Calculate the hash value we need for the bag attributes. */ - gcry_md_hash_buffer (GCRY_MD_SHA1, sha1hash, cert, certlen); - sprintf (keyidstr, "%02x%02x%02x%02x", - sha1hash[16], sha1hash[17], sha1hash[18], sha1hash[19]); - - /* Encode the certificate. */ - buffer = build_cert_sequence (cert, certlen, sha1hash, keyidstr, - &buflen); - if (!buffer) - goto failure; - - /* Encrypt it. */ - gcry_randomize (salt, 8, GCRY_STRONG_RANDOM); - crypt_block (buffer, buflen, salt, 8, 2048, pw, - GCRY_CIPHER_RFC2268_40, 1); - - /* Encode the encrypted stuff into a bag. */ - seqlist[seqlistidx].buffer = build_cert_bag (buffer, buflen, salt, &n); - seqlist[seqlistidx].length = n; - gcry_free (buffer); - buffer = NULL; - if (!seqlist[seqlistidx].buffer) - goto failure; - seqlistidx++; - } - - - if (kparms) - { - /* Encode the key. */ - buffer = build_key_sequence (kparms, &buflen); - if (!buffer) - goto failure; - - /* Encrypt it. */ - gcry_randomize (salt, 8, GCRY_STRONG_RANDOM); - crypt_block (buffer, buflen, salt, 8, 2048, pw, GCRY_CIPHER_3DES, 1); - - /* Encode the encrypted stuff into a bag. */ - if (cert && certlen) - seqlist[seqlistidx].buffer = build_key_bag (buffer, buflen, salt, - sha1hash, keyidstr, &n); - else - seqlist[seqlistidx].buffer = build_key_bag (buffer, buflen, salt, - NULL, NULL, &n); - seqlist[seqlistidx].length = n; - gcry_free (buffer); - buffer = NULL; - if (!seqlist[seqlistidx].buffer) - goto failure; - seqlistidx++; - } - - seqlist[seqlistidx].buffer = NULL; - seqlist[seqlistidx].length = 0; - - buffer = create_final (seqlist, pw, &buflen); - - failure: - if (pwbuf) - { - wipememory (pwbuf, pwbufsize); - gcry_free (pwbuf); - } - for ( ; seqlistidx; seqlistidx--) - gcry_free (seqlist[seqlistidx].buffer); - - *r_length = buffer? buflen : 0; - return buffer; -} - - -#ifdef TEST - -static void -cert_cb (void *opaque, const unsigned char *cert, size_t certlen) -{ - printf ("got a certificate of %u bytes length\n", certlen); -} - -int -main (int argc, char **argv) -{ - FILE *fp; - struct stat st; - unsigned char *buf; - size_t buflen; - gcry_mpi_t *result; - - if (argc != 3) - { - fprintf (stderr, "usage: testp12 file passphrase\n"); - return 1; - } - - gcry_control (GCRYCTL_DISABLE_SECMEM, NULL); - gcry_control (GCRYCTL_INITIALIZATION_FINISHED, NULL); - - fp = fopen (argv[1], "rb"); - if (!fp) - { - fprintf (stderr, "can't open `%s': %s\n", argv[1], strerror (errno)); - return 1; - } - - if (fstat (fileno(fp), &st)) - { - fprintf (stderr, "can't stat `%s': %s\n", argv[1], strerror (errno)); - return 1; - } - - buflen = st.st_size; - buf = gcry_malloc (buflen+1); - if (!buf || fread (buf, buflen, 1, fp) != 1) - { - fprintf (stderr, "error reading `%s': %s\n", argv[1], strerror (errno)); - return 1; - } - fclose (fp); - - result = p12_parse (buf, buflen, argv[2], cert_cb, NULL); - if (result) - { - int i, rc; - unsigned char *tmpbuf; - - for (i=0; result[i]; i++) - { - rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, &tmpbuf, - NULL, result[i]); - if (rc) - printf ("%d: [error printing number: %s]\n", - i, gpg_strerror (rc)); - else - { - printf ("%d: %s\n", i, tmpbuf); - gcry_free (tmpbuf); - } - } - } - - return 0; - -} - -/* -Local Variables: -compile-command: "gcc -Wall -O0 -g -DTEST=1 -o minip12 minip12.c ../common/libcommon.a -L /usr/local/lib -lgcrypt -lgpg-error" -End: -*/ -#endif /* TEST */ diff --git a/agent/minip12.h b/agent/minip12.h deleted file mode 100644 index 998f82f6a..000000000 --- a/agent/minip12.h +++ /dev/null @@ -1,36 +0,0 @@ -/* minip12.h - Global definitions for the minimal pkcs-12 implementation. - * Copyright (C) 2002, 2003 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef MINIP12_H -#define MINIP12_H - -#include <gcrypt.h> - -gcry_mpi_t *p12_parse (const unsigned char *buffer, size_t length, - const char *pw, - void (*certcb)(void*, const unsigned char*, size_t), - void *certcbarg); - -unsigned char *p12_build (gcry_mpi_t *kparms, - unsigned char *cert, size_t certlen, - const char *pw, const char *charset, - size_t *r_length); - - -#endif /*MINIP12_H*/ diff --git a/agent/preset-passphrase.c b/agent/preset-passphrase.c index ae202bf65..2037d9571 100644 --- a/agent/preset-passphrase.c +++ b/agent/preset-passphrase.c @@ -43,7 +43,6 @@ #define JNLIB_NEED_LOG_LOGV #include "agent.h" -#include "minip12.h" #include "simple-pwquery.h" #include "i18n.h" #include "sysutils.h" diff --git a/agent/protect-tool.c b/agent/protect-tool.c index 38debb956..48186d2ac 100644 --- a/agent/protect-tool.c +++ b/agent/protect-tool.c @@ -40,7 +40,6 @@ #define JNLIB_NEED_LOG_LOGV #include "agent.h" -#include "minip12.h" #include "i18n.h" #include "get-passphrase.h" #include "sysutils.h" @@ -63,8 +62,6 @@ enum cmd_and_opt_values oS2Kcalibration, oCanonical, - oP12Import, - oP12Export, oP12Charset, oStore, oForce, @@ -116,11 +113,6 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_c (oShadow, "shadow", "create a shadow entry for a public key"), ARGPARSE_c (oShowShadowInfo, "show-shadow-info", "return the shadow info"), ARGPARSE_c (oShowKeygrip, "show-keygrip", "show the \"keygrip\""), - ARGPARSE_c (oP12Import, "p12-import", - "import a pkcs#12 encoded private key"), - ARGPARSE_c (oP12Export, "p12-export", - "export a private key pkcs#12 encoded"), - ARGPARSE_c (oS2Kcalibration, "s2k-calibration", "@"), ARGPARSE_group (301, N_("@\nOptions:\n ")), @@ -635,7 +627,7 @@ rsa_key_check (struct rsa_secret_key_s *skey) return err? -1:0; } - +#if 0 /* A callback used by p12_parse to return a certificate. */ static void import_p12_cert_cb (void *opaque, const unsigned char *cert, size_t certlen) @@ -793,6 +785,7 @@ import_p12_file (const char *fname) xfree (result); } +#endif @@ -865,6 +858,7 @@ is_keygrip (const char *string) } +#if 0 static void export_p12_file (const char *fname) { @@ -1009,6 +1003,7 @@ export_p12_file (const char *fname) fwrite (key, keylen, 1, stdout); xfree (key); } +#endif @@ -1059,8 +1054,6 @@ main (int argc, char **argv ) case oShadow: cmd = oShadow; break; case oShowShadowInfo: cmd = oShowShadowInfo; break; case oShowKeygrip: cmd = oShowKeygrip; break; - case oP12Import: cmd = oP12Import; break; - case oP12Export: cmd = oP12Export; break; case oP12Charset: opt_p12_charset = pargs.r.ret_str; break; case oS2Kcalibration: cmd = oS2Kcalibration; break; @@ -1105,10 +1098,6 @@ main (int argc, char **argv ) show_shadow_info (fname); else if (cmd == oShowKeygrip) show_keygrip (fname); - else if (cmd == oP12Import) - import_p12_file (fname); - else if (cmd == oP12Export) - export_p12_file (fname); else if (cmd == oS2Kcalibration) { if (!opt.verbose) diff --git a/agent/protect.c b/agent/protect.c index 7f3c1cc42..db6caa48c 100644 --- a/agent/protect.c +++ b/agent/protect.c @@ -415,7 +415,7 @@ agent_protect (const unsigned char *plainkey, const char *passphrase, unsigned char *p; gcry_md_hd_t md; - /* Create an S-expression with the procted-at timestamp. */ + /* Create an S-expression with the protected-at timestamp. */ memcpy (timestamp_exp, "(12:protected-at15:", 19); gnupg_get_isotime (timestamp_exp+19); timestamp_exp[19+15] = ')'; |