aboutsummaryrefslogtreecommitdiffstats
path: root/agent
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2010-06-17 15:44:44 +0000
committerWerner Koch <[email protected]>2010-06-17 15:44:44 +0000
commit006fd75aea5cc766bc223e435e5a07b543d658d3 (patch)
tree2f4365e73bf0a8b5272426fcf1fde9b75be4002e /agent
parentAdd makefiles to build a w32 development package. (diff)
downloadgnupg-006fd75aea5cc766bc223e435e5a07b543d658d3.tar.gz
gnupg-006fd75aea5cc766bc223e435e5a07b543d658d3.zip
Avoid using the protect-tool to import pkcs#12.
Diffstat (limited to 'agent')
-rw-r--r--agent/ChangeLog26
-rw-r--r--agent/Makefile.am3
-rw-r--r--agent/agent.h2
-rw-r--r--agent/command.c278
-rw-r--r--agent/findkey.c6
-rw-r--r--agent/genkey.c199
-rw-r--r--agent/minip12.c2360
-rw-r--r--agent/minip12.h36
-rw-r--r--agent/preset-passphrase.c1
-rw-r--r--agent/protect-tool.c19
-rw-r--r--agent/protect.c2
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] = ')';