Implement export of pkcs#12 objects using a direct agent connection.

This commit is contained in:
Werner Koch 2010-06-21 10:01:24 +00:00
parent 006fd75aea
commit 91056b1976
15 changed files with 458 additions and 408 deletions

View File

@ -1,3 +1,9 @@
2010-06-18 Werner Koch <wk@g10code.com>
* protect-tool.c (store_private_key, rsa_key_check):
* command.c (cmd_export_key): New.
2010-06-15 Werner Koch <wk@g10code.com> 2010-06-15 Werner Koch <wk@g10code.com>
* command.c (cmd_keywrap_key, cmd_import_key): New. * command.c (cmd_keywrap_key, cmd_import_key): New.
@ -2652,7 +2658,7 @@ Fri Aug 18 14:27:14 CEST 2000 Werner Koch <wk@openit.de>
Copyright 2001, 2002, 2003, 2004, 2005, Copyright 2001, 2002, 2003, 2004, 2005,
2007, 2008, 2009 Free Software Foundation, Inc. 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
This file is free software; as a special exception the author gives This file is free software; as a special exception the author gives
unlimited permission to copy and/or distribute it, with or without unlimited permission to copy and/or distribute it, with or without

View File

@ -1,6 +1,6 @@
/* command.c - gpg-agent command handler /* command.c - gpg-agent command handler
* Copyright (C) 2001, 2002, 2003, 2004, 2005, * Copyright (C) 2001, 2002, 2003, 2004, 2005,
* 2006, 2008, 2009 Free Software Foundation, Inc. * 2006, 2008, 2009, 2010 Free Software Foundation, Inc.
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -38,6 +38,8 @@
#include <assuan.h> #include <assuan.h>
#include "i18n.h" #include "i18n.h"
/* Maximum allowed size of the inquired ciphertext. */ /* Maximum allowed size of the inquired ciphertext. */
#define MAXLEN_CIPHERTEXT 4096 #define MAXLEN_CIPHERTEXT 4096
/* Maximum allowed size of the key parameters. */ /* Maximum allowed size of the key parameters. */
@ -564,7 +566,7 @@ cmd_sigkey (assuan_context_t ctx, char *line)
static const char hlp_setkeydesc[] = static const char hlp_setkeydesc[] =
"SETKEYDESC plus_percent_escaped_string\n" "SETKEYDESC plus_percent_escaped_string\n"
"\n" "\n"
"Set a description to be used for the next PKSIGN or PKDECRYPT\n" "Set a description to be used for the next PKSIGN, PKDECRYPT or EXPORT_KEY\n"
"operation if this operation requires the entry of a passphrase. If\n" "operation if this operation requires the entry of a passphrase. If\n"
"this command is not used a default text will be used. Note, that\n" "this command is not used a default text will be used. Note, that\n"
"this description implictly selects the label used for the entry\n" "this description implictly selects the label used for the entry\n"
@ -573,8 +575,8 @@ static const char hlp_setkeydesc[] =
"\"passphrase\" is used. The description string should not contain\n" "\"passphrase\" is used. The description string should not contain\n"
"blanks unless they are percent or '+' escaped.\n" "blanks unless they are percent or '+' escaped.\n"
"\n" "\n"
"The description is only valid for the next PKSIGN or PKDECRYPT\n" "The description is only valid for the next PKSIGN, PKDECRYPT or\n"
"operation."; "EXPORT_KEY operation.";
static gpg_error_t static gpg_error_t
cmd_setkeydesc (assuan_context_t ctx, char *line) cmd_setkeydesc (assuan_context_t ctx, char *line)
{ {
@ -1481,7 +1483,7 @@ cmd_import_key (assuan_context_t ctx, char *line)
if (!ctrl->server_local->import_key) if (!ctrl->server_local->import_key)
{ {
err = gpg_error (GPG_ERR_BAD_KEY); err = gpg_error (GPG_ERR_MISSING_KEY);
goto leave; goto leave;
} }
@ -1562,15 +1564,97 @@ cmd_import_key (assuan_context_t ctx, char *line)
static const char hlp_export_key[] = static const char hlp_export_key[] =
"EXPORT_KEY\n" "EXPORT_KEY <hexstring_with_keygrip>\n"
"\n"; "\n"
"Export a secret key from the key store. The key will be encrypted\n"
"using the current session's key wrapping key (cf. command KEYWRAP_KEY)\n"
"using the AESWRAP-128 algorithm. The caller needs to retrieve that key\n"
"prior to using this command. The function takes the keygrip as argument.\n";
static gpg_error_t static gpg_error_t
cmd_export_key (assuan_context_t ctx, char *line) cmd_export_key (assuan_context_t ctx, char *line)
{ {
gpg_error_t err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err;
unsigned char grip[20];
gcry_sexp_t s_skey = NULL;
unsigned char *key = NULL;
size_t keylen;
gcry_cipher_hd_t cipherhd = NULL;
unsigned char *wrappedkey = NULL;
size_t wrappedkeylen;
if (!ctrl->server_local->export_key)
{
err = gpg_error (GPG_ERR_MISSING_KEY);
goto leave;
}
/* leave: */ err = parse_keygrip (ctx, line, grip);
if (err)
goto leave;
if (agent_key_available (grip))
{
err = gpg_error (GPG_ERR_NO_SECKEY);
goto leave;
}
err = agent_key_from_file (ctrl, ctrl->server_local->keydesc, grip,
NULL, CACHE_MODE_IGNORE, NULL, &s_skey);
if (err)
goto leave;
if (!s_skey)
{
/* Key is on a smartcard. Actually we should not see this here
because we do not pass a shadow_info variable to the above
function, thus it will return this error directly. */
err = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
goto leave;
}
err = make_canon_sexp_pad (s_skey, 1, &key, &keylen);
if (err)
goto leave;
gcry_sexp_release (s_skey);
s_skey = NULL;
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->export_key, KEYWRAP_KEYSIZE);
if (err)
goto leave;
wrappedkeylen = keylen + 8;
wrappedkey = xtrymalloc (wrappedkeylen);
if (!wrappedkey)
{
err = gpg_error_from_syserror ();
goto leave;
}
err = gcry_cipher_encrypt (cipherhd, wrappedkey, wrappedkeylen, key, keylen);
if (err)
goto leave;
xfree (key);
key = NULL;
gcry_cipher_close (cipherhd);
cipherhd = NULL;
assuan_begin_confidential (ctx);
err = assuan_send_data (ctx, wrappedkey, wrappedkeylen);
assuan_end_confidential (ctx);
leave:
xfree (wrappedkey);
gcry_cipher_close (cipherhd);
xfree (key);
gcry_sexp_release (s_skey);
xfree (ctrl->server_local->keydesc);
ctrl->server_local->keydesc = NULL;
return leave_cmd (ctx, err); return leave_cmd (ctx, err);
} }

View File

@ -544,88 +544,6 @@ show_keygrip (const char *fname)
} }
static int
rsa_key_check (struct rsa_secret_key_s *skey)
{
int err = 0;
gcry_mpi_t t = gcry_mpi_snew (0);
gcry_mpi_t t1 = gcry_mpi_snew (0);
gcry_mpi_t t2 = gcry_mpi_snew (0);
gcry_mpi_t phi = gcry_mpi_snew (0);
/* check that n == p * q */
gcry_mpi_mul (t, skey->p, skey->q);
if (gcry_mpi_cmp( t, skey->n) )
{
log_error ("RSA oops: n != p * q\n");
err++;
}
/* check that p is less than q */
if (gcry_mpi_cmp (skey->p, skey->q) > 0)
{
gcry_mpi_t tmp;
log_info ("swapping secret primes\n");
tmp = gcry_mpi_copy (skey->p);
gcry_mpi_set (skey->p, skey->q);
gcry_mpi_set (skey->q, tmp);
gcry_mpi_release (tmp);
/* and must recompute u of course */
gcry_mpi_invm (skey->u, skey->p, skey->q);
}
/* check that e divides neither p-1 nor q-1 */
gcry_mpi_sub_ui (t, skey->p, 1 );
gcry_mpi_div (NULL, t, t, skey->e, 0);
if (!gcry_mpi_cmp_ui( t, 0) )
{
log_error ("RSA oops: e divides p-1\n");
err++;
}
gcry_mpi_sub_ui (t, skey->q, 1);
gcry_mpi_div (NULL, t, t, skey->e, 0);
if (!gcry_mpi_cmp_ui( t, 0))
{
log_info ( "RSA oops: e divides q-1\n" );
err++;
}
/* check that d is correct. */
gcry_mpi_sub_ui (t1, skey->p, 1);
gcry_mpi_sub_ui (t2, skey->q, 1);
gcry_mpi_mul (phi, t1, t2);
gcry_mpi_invm (t, skey->e, phi);
if (gcry_mpi_cmp (t, skey->d))
{ /* no: try universal exponent. */
gcry_mpi_gcd (t, t1, t2);
gcry_mpi_div (t, NULL, phi, t, 0);
gcry_mpi_invm (t, skey->e, t);
if (gcry_mpi_cmp (t, skey->d))
{
log_error ("RSA oops: bad secret exponent\n");
err++;
}
}
/* check for correctness of u */
gcry_mpi_invm (t, skey->p, skey->q);
if (gcry_mpi_cmp (t, skey->u))
{
log_info ( "RSA oops: bad u parameter\n");
err++;
}
if (err)
log_info ("RSA secret key check failed\n");
gcry_mpi_release (t);
gcry_mpi_release (t1);
gcry_mpi_release (t2);
gcry_mpi_release (phi);
return err? -1:0;
}
#if 0 #if 0
/* A callback used by p12_parse to return a certificate. */ /* A callback used by p12_parse to return a certificate. */
@ -789,6 +707,7 @@ import_p12_file (const char *fname)
#if 0
static gcry_mpi_t * static gcry_mpi_t *
sexp_to_kparms (gcry_sexp_t sexp) sexp_to_kparms (gcry_sexp_t sexp)
{ {
@ -842,20 +761,20 @@ sexp_to_kparms (gcry_sexp_t sexp)
gcry_sexp_release (list); gcry_sexp_release (list);
return array; return array;
} }
#endif
/* Check whether STRING is a KEYGRIP, i.e has the correct length and /* Check whether STRING is a KEYGRIP, i.e has the correct length and
does only consist of uppercase hex characters. */ does only consist of uppercase hex characters. */
static int /* static int */
is_keygrip (const char *string) /* is_keygrip (const char *string) */
{ /* { */
int i; /* int i; */
for(i=0; string[i] && i < 41; i++) /* for(i=0; string[i] && i < 41; i++) */
if (!strchr("01234567890ABCDEF", string[i])) /* if (!strchr("01234567890ABCDEF", string[i])) */
return 0; /* return 0; */
return i == 40; /* return i == 40; */
} /* } */
#if 0 #if 0
@ -1195,6 +1114,7 @@ release_passphrase (char *pw)
} }
} }
#if 0
static int static int
store_private_key (const unsigned char *grip, store_private_key (const unsigned char *grip,
const void *buffer, size_t length, int force) const void *buffer, size_t length, int force)
@ -1257,3 +1177,4 @@ store_private_key (const unsigned char *grip,
xfree (fname); xfree (fname);
return 0; return 0;
} }
#endif

View File

@ -1,3 +1,13 @@
2010-06-21 Werner Koch <wk@g10code.com>
* util.h (xfree_fnc): New.
2010-06-18 Werner Koch <wk@g10code.com>
* util.h (GPG_ERR_MISSING_KEY) [!GPG_ERR_MISSING_KEY]: New.
* sexputil.c (make_canon_sexp_pad): Add arg SECURE.
2010-06-17 Werner Koch <wk@g10code.com> 2010-06-17 Werner Koch <wk@g10code.com>
* sexputil.c (make_canon_sexp_pad): New. * sexputil.c (make_canon_sexp_pad): New.

View File

@ -72,9 +72,9 @@ make_canon_sexp (gcry_sexp_t sexp, unsigned char **r_buffer, size_t *r_buflen)
/* Same as make_canon_sexp but pad the buffer to multiple of 64 /* Same as make_canon_sexp but pad the buffer to multiple of 64
bits. */ bits. If SECURE is set, secure memory will be allocated. */
gpg_error_t gpg_error_t
make_canon_sexp_pad (gcry_sexp_t sexp, make_canon_sexp_pad (gcry_sexp_t sexp, int secure,
unsigned char **r_buffer, size_t *r_buflen) unsigned char **r_buffer, size_t *r_buflen)
{ {
size_t len; size_t len;
@ -88,7 +88,7 @@ make_canon_sexp_pad (gcry_sexp_t sexp,
if (!len) if (!len)
return gpg_error (GPG_ERR_BUG); return gpg_error (GPG_ERR_BUG);
len += (8 - len % 8) % 8; len += (8 - len % 8) % 8;
buf = xtrycalloc (1, len); buf = secure? xtrycalloc_secure (1, len) : xtrycalloc (1, len);
if (!buf) if (!buf)
return gpg_error_from_syserror (); return gpg_error_from_syserror ();
if (!gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, buf, len)) if (!gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, buf, len))

View File

@ -23,6 +23,10 @@
#include <gcrypt.h> /* We need this for the memory function protos. */ #include <gcrypt.h> /* We need this for the memory function protos. */
#include <errno.h> /* We need errno. */ #include <errno.h> /* We need errno. */
#include <gpg-error.h> /* We need gpg_error_t. */ #include <gpg-error.h> /* We need gpg_error_t. */
/* Add error codes available only in newer versions of libgpg-error. */
#ifndef GPG_ERR_MISSING_KEY
#define GPG_ERR_MISSING_KEY 181
#endif
/* Hash function used with libksba. */ /* Hash function used with libksba. */
#define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write) #define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write)
@ -77,6 +81,7 @@ typedef char **rl_completion_func_t (const char *, int, int);
#define xtryrealloc(a,b) gcry_realloc ((a),(b)) #define xtryrealloc(a,b) gcry_realloc ((a),(b))
#define xtrystrdup(a) gcry_strdup ((a)) #define xtrystrdup(a) gcry_strdup ((a))
#define xfree(a) gcry_free ((a)) #define xfree(a) gcry_free ((a))
#define xfree_fnc gcry_free
#define xmalloc(a) gcry_xmalloc ((a)) #define xmalloc(a) gcry_xmalloc ((a))
#define xmalloc_secure(a) gcry_xmalloc_secure ((a)) #define xmalloc_secure(a) gcry_xmalloc_secure ((a))
@ -146,7 +151,7 @@ gpg_error_t b64dec_finish (struct b64state *state);
/*-- sexputil.c */ /*-- sexputil.c */
gpg_error_t make_canon_sexp (gcry_sexp_t sexp, gpg_error_t make_canon_sexp (gcry_sexp_t sexp,
unsigned char **r_buffer, size_t *r_buflen); unsigned char **r_buffer, size_t *r_buflen);
gpg_error_t make_canon_sexp_pad (gcry_sexp_t sexp, gpg_error_t make_canon_sexp_pad (gcry_sexp_t sexp, int secure,
unsigned char **r_buffer, size_t *r_buflen); unsigned char **r_buffer, size_t *r_buflen);
gpg_error_t keygrip_from_canon_sexp (const unsigned char *key, size_t keylen, gpg_error_t keygrip_from_canon_sexp (const unsigned char *key, size_t keylen,
unsigned char *grip); unsigned char *grip);

View File

@ -40,7 +40,7 @@ AC_INIT([gnupg],
# sufficient. # sufficient.
development_version=no development_version=no
NEED_GPG_ERROR_VERSION=1.4 NEED_GPG_ERROR_VERSION=1.8
NEED_LIBGCRYPT_API=1 NEED_LIBGCRYPT_API=1
NEED_LIBGCRYPT_VERSION=1.4.0 NEED_LIBGCRYPT_VERSION=1.4.0

View File

@ -1,3 +1,21 @@
2010-06-21 Werner Koch <wk@g10code.com>
* minip12.c (p12_build): Change arg CERT to const void ptr.
(build_cert_sequence): Change arg CERT to const ptr.
* gpgsm.c (main) <aExportSecretKeyP12>: Use to estream.
(open_fwrite): Removed.
* export.c: Include minip12.h.
(popen_protect_tool): Remove.
(export_p12): Use gpg-agent directly. Change calling convention.
(gpgsm_p12_export): Adjust for that change. Change arg FP to an
estream_t.
(do_putc): Remove. Change callers to es_putc.
(do_fputs): Likewise.
(print_short_info): Remove arg FP.
* call-agent.c (gpgsm_agent_export_key): new.
2010-06-17 Werner Koch <wk@g10code.com> 2010-06-17 Werner Koch <wk@g10code.com>
* import.c (parse_p12): Remove arg retfp. Use the agent's new * import.c (parse_p12): Remove arg retfp. Use the agent's new

View File

@ -1079,9 +1079,10 @@ gpgsm_agent_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno)
/* Ask for the passphrase (this is used for pkcs#12 import/export. On /* Ask for the passphrase (this is used for pkcs#12 import/export. On
success the caller needs to free the string stored at R_PASSPHRASE. success the caller needs to free the string stored at R_PASSPHRASE.
On error NULL will be stored at R_PASSPHRASE and an appropriate On error NULL will be stored at R_PASSPHRASE and an appropriate
error code returned. */ error code returned. If REPEAT is true the agent tries to get a
new passphrase (i.e. asks the user to confirm it). */
gpg_error_t gpg_error_t
gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, int repeat,
char **r_passphrase) char **r_passphrase)
{ {
gpg_error_t err; gpg_error_t err;
@ -1098,7 +1099,9 @@ gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg,
if (desc_msg && *desc_msg && !(arg4 = percent_plus_escape (desc_msg))) if (desc_msg && *desc_msg && !(arg4 = percent_plus_escape (desc_msg)))
return gpg_error_from_syserror (); return gpg_error_from_syserror ();
snprintf (line, DIM(line)-1, "GET_PASSPHRASE --data -- X X X %s", arg4); snprintf (line, DIM(line)-1, "GET_PASSPHRASE --data%s -- X X X %s",
repeat? " --repeat=1 --check --qualitybar":"",
arg4);
xfree (arg4); xfree (arg4);
init_membuf_secure (&data, 64); init_membuf_secure (&data, 64);
@ -1201,3 +1204,55 @@ gpgsm_agent_import_key (ctrl_t ctrl, const void *key, size_t keylen)
NULL, NULL, inq_import_key_parms, &parm, NULL, NULL); NULL, NULL, inq_import_key_parms, &parm, NULL, NULL);
return err; return err;
} }
/* Receive a secret key from the agent. KEYGRIP is the hexified
keygrip, DESC a prompt to be displayed with the agent's passphrase
question (needs to be plus+percent escaped). On success the key is
stored as a canonical S-expression at R_RESULT and R_RESULTLEN. */
gpg_error_t
gpgsm_agent_export_key (ctrl_t ctrl, const char *keygrip, const char *desc,
unsigned char **r_result, size_t *r_resultlen)
{
gpg_error_t err;
membuf_t data;
size_t len;
unsigned char *buf;
char line[ASSUAN_LINELENGTH];
*r_result = NULL;
err = start_agent (ctrl);
if (err)
return err;
if (desc)
{
snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
err = assuan_transact (agent_ctx, line,
NULL, NULL, NULL, NULL, NULL, NULL);
if (err)
return err;
}
snprintf (line, DIM(line)-1, "EXPORT_KEY %s", keygrip);
init_membuf_secure (&data, 1024);
err = assuan_transact (agent_ctx, line,
membuf_data_cb, &data,
default_inq_cb, ctrl, NULL, NULL);
if (err)
{
xfree (get_membuf (&data, &len));
return err;
}
buf = get_membuf (&data, &len);
if (!buf)
return gpg_error_from_syserror ();
*r_result = buf;
*r_resultlen = len;
return 0;
}

View File

@ -34,8 +34,7 @@
#include "exechelp.h" #include "exechelp.h"
#include "i18n.h" #include "i18n.h"
#include "sysutils.h" #include "sysutils.h"
#include "minip12.h"
/* A table to store a fingerprint as used in a duplicates table. We /* A table to store a fingerprint as used in a duplicates table. We
don't need to hash here because a fingerprint is already a perfect don't need to hash here because a fingerprint is already a perfect
@ -57,11 +56,11 @@ typedef struct duptable_s *duptable_t;
#define DUPTABLE_SIZE (1 << DUPTABLE_BITS) #define DUPTABLE_SIZE (1 << DUPTABLE_BITS)
static void print_short_info (ksba_cert_t cert, FILE *fp, estream_t stream); static void print_short_info (ksba_cert_t cert, estream_t stream);
static gpg_error_t export_p12 (ctrl_t ctrl, static gpg_error_t export_p12 (ctrl_t ctrl,
const unsigned char *certimg, size_t certimglen, const unsigned char *certimg, size_t certimglen,
const char *prompt, const char *keygrip, const char *prompt, const char *keygrip,
estream_t *retfp); void **r_result, size_t *r_resultlen);
/* Create a table used to indetify duplicated certificates. */ /* Create a table used to indetify duplicated certificates. */
@ -255,7 +254,7 @@ gpgsm_export (ctrl_t ctrl, strlist_t names, estream_t stream)
{ {
if (count) if (count)
es_putc ('\n', stream); es_putc ('\n', stream);
print_short_info (cert, NULL, stream); print_short_info (cert, stream);
es_putc ('\n', stream); es_putc ('\n', stream);
} }
count++; count++;
@ -317,23 +316,22 @@ gpgsm_export (ctrl_t ctrl, strlist_t names, estream_t stream)
} }
/* Export a certificates and its private key. */ /* Export a certificate and its private key. */
void void
gpgsm_p12_export (ctrl_t ctrl, const char *name, FILE *fp) gpgsm_p12_export (ctrl_t ctrl, const char *name, estream_t stream)
{ {
gpg_error_t err = 0;
KEYDB_HANDLE hd; KEYDB_HANDLE hd;
KEYDB_SEARCH_DESC *desc = NULL; KEYDB_SEARCH_DESC *desc = NULL;
Base64Context b64writer = NULL; Base64Context b64writer = NULL;
ksba_writer_t writer; ksba_writer_t writer;
ksba_cert_t cert = NULL; ksba_cert_t cert = NULL;
int rc=0;
const unsigned char *image; const unsigned char *image;
size_t imagelen; size_t imagelen;
char *keygrip = NULL; char *keygrip = NULL;
char *prompt; char *prompt;
char buffer[1024]; void *data;
int nread; size_t datalen;
estream_t datafp = NULL;
hd = keydb_new (0); hd = keydb_new (0);
@ -351,28 +349,28 @@ gpgsm_p12_export (ctrl_t ctrl, const char *name, FILE *fp)
goto leave; goto leave;
} }
rc = classify_user_id (name, desc); err = classify_user_id (name, desc);
if (rc) if (err)
{ {
log_error ("key `%s' not found: %s\n", log_error ("key `%s' not found: %s\n",
name, gpg_strerror (rc)); name, gpg_strerror (err));
goto leave; goto leave;
} }
/* Lookup the certificate and make sure that it is unique. */ /* Lookup the certificate and make sure that it is unique. */
rc = keydb_search (hd, desc, 1); err = keydb_search (hd, desc, 1);
if (!rc) if (!err)
{ {
rc = keydb_get_cert (hd, &cert); err = keydb_get_cert (hd, &cert);
if (rc) if (err)
{ {
log_error ("keydb_get_cert failed: %s\n", gpg_strerror (rc)); log_error ("keydb_get_cert failed: %s\n", gpg_strerror (err));
goto leave; goto leave;
} }
next_ambiguous: next_ambiguous:
rc = keydb_search (hd, desc, 1); err = keydb_search (hd, desc, 1);
if (!rc) if (!err)
{ {
ksba_cert_t cert2 = NULL; ksba_cert_t cert2 = NULL;
@ -385,14 +383,14 @@ gpgsm_p12_export (ctrl_t ctrl, const char *name, FILE *fp)
} }
ksba_cert_release (cert2); ksba_cert_release (cert2);
} }
rc = gpg_error (GPG_ERR_AMBIGUOUS_NAME); err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
} }
else if (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF) else if (err == -1 || gpg_err_code (err) == GPG_ERR_EOF)
rc = 0; err = 0;
if (rc) if (err)
{ {
log_error ("key `%s' not found: %s\n", log_error ("key `%s' not found: %s\n",
name, gpg_strerror (rc)); name, gpg_strerror (err));
goto leave; goto leave;
} }
} }
@ -401,8 +399,8 @@ gpgsm_p12_export (ctrl_t ctrl, const char *name, FILE *fp)
if (!keygrip || gpgsm_agent_havekey (ctrl, keygrip)) if (!keygrip || gpgsm_agent_havekey (ctrl, keygrip))
{ {
/* Note, that the !keygrip case indicates a bad certificate. */ /* Note, that the !keygrip case indicates a bad certificate. */
rc = gpg_error (GPG_ERR_NO_SECKEY); err = gpg_error (GPG_ERR_NO_SECKEY);
log_error ("can't export key `%s': %s\n", name, gpg_strerror (rc)); log_error ("can't export key `%s': %s\n", name, gpg_strerror (err));
goto leave; goto leave;
} }
@ -415,51 +413,44 @@ gpgsm_p12_export (ctrl_t ctrl, const char *name, FILE *fp)
if (ctrl->create_pem) if (ctrl->create_pem)
{ {
print_short_info (cert, fp, NULL); print_short_info (cert, stream);
putc ('\n', fp); es_putc ('\n', stream);
} }
if (opt.p12_charset && ctrl->create_pem) if (opt.p12_charset && ctrl->create_pem)
{ {
fprintf (fp, "The passphrase is %s encoded.\n\n", es_fprintf (stream, "The passphrase is %s encoded.\n\n",
opt.p12_charset); opt.p12_charset);
} }
ctrl->pem_name = "PKCS12"; ctrl->pem_name = "PKCS12";
rc = gpgsm_create_writer (&b64writer, ctrl, fp, NULL, &writer); err = gpgsm_create_writer (&b64writer, ctrl, NULL, stream, &writer);
if (rc) if (err)
{ {
log_error ("can't create writer: %s\n", gpg_strerror (rc)); log_error ("can't create writer: %s\n", gpg_strerror (err));
goto leave; goto leave;
} }
prompt = gpgsm_format_keydesc (cert); prompt = gpgsm_format_keydesc (cert);
rc = export_p12 (ctrl, image, imagelen, prompt, keygrip, &datafp); err = export_p12 (ctrl, image, imagelen, prompt, keygrip, &data, &datalen);
xfree (prompt); xfree (prompt);
if (rc) if (err)
goto leave; goto leave;
es_rewind (datafp); err = ksba_writer_write (writer, data, datalen);
while ( (nread = es_fread (buffer, 1, sizeof buffer, datafp)) > 0 ) xfree (data);
if ((rc = ksba_writer_write (writer, buffer, nread))) if (err)
{
log_error ("write failed: %s\n", gpg_strerror (rc));
goto leave;
}
if (es_ferror (datafp))
{ {
rc = gpg_error_from_syserror (); log_error ("write failed: %s\n", gpg_strerror (err));
log_error ("error reading temporary file: %s\n", gpg_strerror (rc));
goto leave; goto leave;
} }
if (ctrl->create_pem) if (ctrl->create_pem)
{ {
/* We want one certificate per PEM block */ /* We want one certificate per PEM block */
rc = gpgsm_finish_writer (b64writer); err = gpgsm_finish_writer (b64writer);
if (rc) if (err)
{ {
log_error ("write failed: %s\n", gpg_strerror (rc)); log_error ("write failed: %s\n", gpg_strerror (err));
goto leave; goto leave;
} }
gpgsm_destroy_writer (b64writer); gpgsm_destroy_writer (b64writer);
@ -470,7 +461,6 @@ gpgsm_p12_export (ctrl_t ctrl, const char *name, FILE *fp)
cert = NULL; cert = NULL;
leave: leave:
es_fclose (datafp);
gpgsm_destroy_writer (b64writer); gpgsm_destroy_writer (b64writer);
ksba_cert_release (cert); ksba_cert_release (cert);
xfree (desc); xfree (desc);
@ -478,30 +468,9 @@ gpgsm_p12_export (ctrl_t ctrl, const char *name, FILE *fp)
} }
/* Call either es_putc or the plain putc. */
static void
do_putc (int value, FILE *fp, estream_t stream)
{
if (stream)
es_putc (value, stream);
else
putc (value, fp);
}
/* Call either es_fputs or the plain fputs. */
static void
do_fputs (const char *string, FILE *fp, estream_t stream)
{
if (stream)
es_fputs (string, stream);
else
fputs (string, fp);
}
/* Print some info about the certifciate CERT to FP or STREAM */ /* Print some info about the certifciate CERT to FP or STREAM */
static void static void
print_short_info (ksba_cert_t cert, FILE *fp, estream_t stream) print_short_info (ksba_cert_t cert, estream_t stream)
{ {
char *p; char *p;
ksba_sexp_t sexp; ksba_sexp_t sexp;
@ -509,18 +478,15 @@ print_short_info (ksba_cert_t cert, FILE *fp, estream_t stream)
for (idx=0; (p = ksba_cert_get_issuer (cert, idx)); idx++) for (idx=0; (p = ksba_cert_get_issuer (cert, idx)); idx++)
{ {
do_fputs ((!idx es_fputs ((!idx
? "Issuer ...: " ? "Issuer ...: "
: "\n aka ...: "), fp, stream); : "\n aka ...: "), stream);
if (stream) gpgsm_es_print_name (stream, p);
gpgsm_es_print_name (stream, p);
else
gpgsm_print_name (fp, p);
xfree (p); xfree (p);
} }
do_putc ('\n', fp, stream); es_putc ('\n', stream);
do_fputs ("Serial ...: ", fp, stream); es_fputs ("Serial ...: ", stream);
sexp = ksba_cert_get_serial (cert); sexp = ksba_cert_get_serial (cert);
if (sexp) if (sexp)
{ {
@ -533,199 +499,208 @@ print_short_info (ksba_cert_t cert, FILE *fp, estream_t stream)
for (len=0; *s && *s != ':' && digitp (s); s++) for (len=0; *s && *s != ':' && digitp (s); s++)
len = len*10 + atoi_1 (s); len = len*10 + atoi_1 (s);
if (*s == ':') if (*s == ':')
{ es_write_hexstring (stream, s+1, len, 0, NULL);
if (stream)
es_write_hexstring (stream, s+1, len, 0, NULL);
else
print_hexstring (fp, s+1, len, 0);
}
} }
xfree (sexp); xfree (sexp);
} }
do_putc ('\n', fp, stream); es_putc ('\n', stream);
for (idx=0; (p = ksba_cert_get_subject (cert, idx)); idx++) for (idx=0; (p = ksba_cert_get_subject (cert, idx)); idx++)
{ {
do_fputs ((!idx es_fputs ((!idx
? "Subject ..: " ? "Subject ..: "
: "\n aka ..: "), fp, stream); : "\n aka ..: "), stream);
if (stream) gpgsm_es_print_name (stream, p);
gpgsm_es_print_name (stream, p);
else
gpgsm_print_name (fp, p);
xfree (p); xfree (p);
} }
do_putc ('\n', fp, stream); es_putc ('\n', stream);
} }
static gpg_error_t
popen_protect_tool (ctrl_t ctrl, const char *pgmname, /* Parse a private key S-expression and retutn a malloced array with
estream_t infile, estream_t outfile, the RSA paramaters in pkcs#12 order. The caller needs to
estream_t *statusfile, deep-release this array. */
const char *prompt, const char *keygrip, static gcry_mpi_t *
pid_t *pid) sexp_to_kparms (gcry_sexp_t sexp)
{ {
const char *argv[22]; gcry_sexp_t list, l2;
int i=0; const char *name;
const char *s;
size_t n;
int idx;
const char *elems;
gcry_mpi_t *array;
/* Make sure that the agent is running so that the protect tool is list = gcry_sexp_find_token (sexp, "private-key", 0 );
able to ask for a passphrase. This has only an effect under W32 if(!list)
where the agent is started on demand; sending a NOP does not harm return NULL;
on other platforms. This is not really necessary anymore because l2 = gcry_sexp_cadr (list);
the protect tool does this now by itself; it does not harm either.*/ gcry_sexp_release (list);
gpgsm_agent_send_nop (ctrl); list = l2;
name = gcry_sexp_nth_data (list, 0, &n);
argv[i++] = "--homedir"; if(!name || n != 3 || memcmp (name, "rsa", 3))
argv[i++] = opt.homedir;
argv[i++] = "--p12-export";
argv[i++] = "--have-cert";
argv[i++] = "--prompt";
argv[i++] = prompt?prompt:"";
argv[i++] = "--enable-status-msg";
if (opt.p12_charset)
{ {
argv[i++] = "--p12-charset"; gcry_sexp_release (list);
argv[i++] = opt.p12_charset; return NULL;
} }
if (opt.agent_program)
{
argv[i++] = "--agent-program";
argv[i++] = opt.agent_program;
}
argv[i++] = "--",
argv[i++] = keygrip,
argv[i] = NULL;
assert (i < sizeof argv);
return gnupg_spawn_process (pgmname, argv, infile, outfile, /* Parameter names used with RSA in the pkcs#12 order. */
setup_pinentry_env, (128|64), elems = "nedqp--u";
statusfile, pid); array = xtrycalloc (strlen(elems) + 1, sizeof *array);
if (!array)
{
gcry_sexp_release (list);
return NULL;
}
for (idx=0, s=elems; *s; s++, idx++ )
{
if (*s == '-')
continue; /* Computed below */
l2 = gcry_sexp_find_token (list, s, 1);
if (l2)
{
array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
gcry_sexp_release (l2);
}
if (!array[idx]) /* Required parameter not found or invalid. */
{
for (idx=0; array[idx]; idx++)
gcry_mpi_release (array[idx]);
xfree (array);
gcry_sexp_release (list);
return NULL;
}
}
gcry_sexp_release (list);
array[5] = gcry_mpi_snew (0); /* compute d mod (q-1) */
gcry_mpi_sub_ui (array[5], array[3], 1);
gcry_mpi_mod (array[5], array[2], array[5]);
array[6] = gcry_mpi_snew (0); /* compute d mod (p-1) */
gcry_mpi_sub_ui (array[6], array[4], 1);
gcry_mpi_mod (array[6], array[3], array[6]);
return array;
} }
static gpg_error_t static gpg_error_t
export_p12 (ctrl_t ctrl, const unsigned char *certimg, size_t certimglen, export_p12 (ctrl_t ctrl, const unsigned char *certimg, size_t certimglen,
const char *prompt, const char *keygrip, estream_t *retfp) const char *prompt, const char *keygrip,
void **r_result, size_t *r_resultlen)
{ {
const char *pgmname; gpg_error_t err = 0;
gpg_error_t err = 0, child_err = 0; void *kek = NULL;
int c, cont_line; size_t keklen;
unsigned int pos; unsigned char *wrappedkey = NULL;
estream_t infp = NULL; size_t wrappedkeylen;
estream_t fp = NULL; gcry_cipher_hd_t cipherhd = NULL;
estream_t outfp = NULL; gcry_sexp_t s_skey = NULL;
char buffer[1024]; gcry_mpi_t *kparms = NULL;
pid_t pid = -1; unsigned char *key = NULL;
int bad_pass = 0; size_t keylen;
char *passphrase = NULL;
unsigned char *result = NULL;
size_t resultlen;
int i;
if (!opt.protect_tool_program || !*opt.protect_tool_program) *r_result = NULL;
pgmname = gnupg_module_name (GNUPG_MODULE_NAME_PROTECT_TOOL);
else
pgmname = opt.protect_tool_program;
infp = es_tmpfile (); /* Get the current KEK. */
if (!infp) err = gpgsm_agent_keywrap_key (ctrl, 1, &kek, &keklen);
{
err = gpg_error_from_syserror ();
log_error (_("error creating temporary file: %s\n"), strerror (errno));
goto cleanup;
}
if (es_fwrite (certimg, certimglen, 1, infp) != 1)
{
err = gpg_error_from_syserror ();
log_error (_("error writing to temporary file: %s\n"),
strerror (errno));
goto cleanup;
}
outfp = es_tmpfile ();
if (!outfp)
{
err = gpg_error_from_syserror ();
log_error (_("error creating temporary file: %s\n"), strerror (errno));
goto cleanup;
}
err = popen_protect_tool (ctrl,
pgmname, infp, outfp, &fp, prompt, keygrip, &pid);
if (err) if (err)
{ {
pid = -1; log_error ("error getting the KEK: %s\n", gpg_strerror (err));
goto cleanup; goto leave;
}
es_fclose (infp);
infp = NULL;
/* Read stderr of the protect tool. */
pos = 0;
cont_line = 0;
while ((c=es_getc (fp)) != EOF)
{
/* fixme: We could here grep for status information of the
protect tool to figure out better error codes for
CHILD_ERR. */
buffer[pos++] = c;
if (pos >= sizeof buffer - 5 || c == '\n')
{
buffer[pos - (c == '\n')] = 0;
if (cont_line)
log_printf ("%s", buffer);
else
{
if (!strncmp (buffer, "gpg-protect-tool: [PROTECT-TOOL:] ",34))
{
char *p, *pend;
p = buffer + 34;
pend = strchr (p, ' ');
if (pend)
*pend = 0;
if ( !strcmp (p, "bad-passphrase"))
bad_pass++;
}
else
log_info ("%s", buffer);
}
pos = 0;
cont_line = (c != '\n');
}
} }
if (pos) /* Receive the wrapped key from the agent. */
{ err = gpgsm_agent_export_key (ctrl, keygrip, prompt,
buffer[pos] = 0; &wrappedkey, &wrappedkeylen);
if (cont_line)
log_printf ("%s\n", buffer);
else
log_info ("%s\n", buffer);
}
else if (cont_line)
log_printf ("\n");
/* If we found no error in the output of the child, setup a suitable
error code, which will later be reset if the exit status of the
child is 0. */
if (!child_err)
child_err = gpg_error (GPG_ERR_DECRYPT_FAILED);
cleanup:
es_fclose (infp);
es_fclose (fp);
if (pid != -1)
{
if (!gnupg_wait_process (pgmname, pid, 0, NULL))
child_err = 0;
gnupg_release_process (pid);
}
if (!err)
err = child_err;
if (err) if (err)
es_fclose (outfp); goto leave;
else
*retfp = outfp;
if (bad_pass) /* Unwrap the key. */
err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128,
GCRY_CIPHER_MODE_AESWRAP, 0);
if (err)
goto leave;
err = gcry_cipher_setkey (cipherhd, kek, keklen);
if (err)
goto leave;
xfree (kek);
kek = NULL;
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_decrypt (cipherhd, key, keylen, wrappedkey, wrappedkeylen);
if (err)
goto leave;
xfree (wrappedkey);
wrappedkey = NULL;
gcry_cipher_close (cipherhd);
cipherhd = NULL;
/* Convert to a gcrypt S-expression. */
err = gcry_sexp_create (&s_skey, key, keylen, 0, xfree_fnc);
if (err)
goto leave;
key = NULL; /* Key is now owned by S_KEY. */
/* Get the parameters from the S-expression. */
kparms = sexp_to_kparms (s_skey);
gcry_sexp_release (s_skey);
s_skey = NULL;
if (!kparms)
{
log_error ("error converting key parameters\n");
err = GPG_ERR_BAD_SECKEY;
goto leave;
}
err = gpgsm_agent_ask_passphrase
(ctrl,
i18n_utf8 ("Please enter the passphrase to protect the "
"new PKCS#12 object."),
1, &passphrase);
if (err)
goto leave;
result = p12_build (kparms, certimg, certimglen, passphrase,
opt.p12_charset, &resultlen);
xfree (passphrase);
passphrase = NULL;
if (!result)
err = gpg_error (GPG_ERR_GENERAL);
leave:
xfree (key);
gcry_sexp_release (s_skey);
if (kparms)
{
for (i=0; kparms[i]; i++)
gcry_mpi_release (kparms[i]);
xfree (kparms);
}
gcry_cipher_close (cipherhd);
xfree (wrappedkey);
xfree (kek);
if (gpg_err_code (err) == GPG_ERR_BAD_PASSPHRASE)
{ {
/* During export this is the passphrase used to unprotect the /* During export this is the passphrase used to unprotect the
key and not the pkcs#12 thing as in export. Therefore we can key and not the pkcs#12 thing as in export. Therefore we can
@ -733,6 +708,16 @@ export_p12 (ctrl_t ctrl, const unsigned char *certimg, size_t certimglen,
zero keyid by a regular one. */ zero keyid by a regular one. */
gpgsm_status (ctrl, STATUS_BAD_PASSPHRASE, "0000000000000000"); gpgsm_status (ctrl, STATUS_BAD_PASSPHRASE, "0000000000000000");
} }
if (err)
{
xfree (result);
}
else
{
*r_result = result;
*r_resultlen = resultlen;
}
return err; return err;
} }

View File

@ -435,7 +435,6 @@ static void emergency_cleanup (void);
static int check_special_filename (const char *fname, int for_write); static int check_special_filename (const char *fname, int for_write);
static int open_read (const char *filename); static int open_read (const char *filename);
static estream_t open_es_fread (const char *filename, const char *mode); static estream_t open_es_fread (const char *filename, const char *mode);
static FILE *open_fwrite (const char *filename);
static estream_t open_es_fwrite (const char *filename); static estream_t open_es_fwrite (const char *filename);
static void run_protect_tool (int argc, char **argv); static void run_protect_tool (int argc, char **argv);
@ -1877,14 +1876,14 @@ main ( int argc, char **argv)
case aExportSecretKeyP12: case aExportSecretKeyP12:
{ {
FILE *fp = open_fwrite (opt.outfile?opt.outfile:"-"); estream_t fp = open_es_fwrite (opt.outfile?opt.outfile:"-");
if (argc == 1) if (argc == 1)
gpgsm_p12_export (&ctrl, *argv, fp); gpgsm_p12_export (&ctrl, *argv, fp);
else else
wrong_args ("--export-secret-key-p12 KEY-ID"); wrong_args ("--export-secret-key-p12 KEY-ID");
if (fp != stdout) if (fp != es_stdout)
fclose (fp); es_fclose (fp);
} }
break; break;
@ -2091,45 +2090,6 @@ open_es_fread (const char *filename, const char *mode)
} }
/* Open FILENAME for fwrite and return the stream. Stop with an error
message in case of problems. "-" denotes stdout and if special
filenames are allowed the given fd is opened instead. Caller must
close the returned stream unless it is stdout. */
static FILE *
open_fwrite (const char *filename)
{
int fd;
FILE *fp;
if (filename[0] == '-' && !filename[1])
{
set_binary (stdout);
return stdout;
}
fd = check_special_filename (filename, 1);
if (fd != -1)
{
#warning replace the line below
fp = NULL; /*fdopen (dup (fd), "wb"); */
if (!fp)
{
log_error ("fdopen(%d) failed: %s\n", fd, strerror (errno));
gpgsm_exit (2);
}
set_binary (fp);
return fp;
}
fp = fopen (filename, "wb");
if (!fp)
{
log_error (_("can't open `%s': %s\n"), filename, strerror (errno));
gpgsm_exit (2);
}
return fp;
}
/* Open FILENAME for fwrite and return an extended stream. Stop with /* Open FILENAME for fwrite and return an extended stream. Stop with
an error message in case of problems. "-" denotes stdout and if an error message in case of problems. "-" denotes stdout and if
special filenames are allowed the given fd is opened instead. special filenames are allowed the given fd is opened instead.

View File

@ -344,7 +344,7 @@ int gpgsm_import_files (ctrl_t ctrl, int nfiles, char **files,
/*-- export.c --*/ /*-- export.c --*/
void gpgsm_export (ctrl_t ctrl, strlist_t names, estream_t stream); void gpgsm_export (ctrl_t ctrl, strlist_t names, estream_t stream);
void gpgsm_p12_export (ctrl_t ctrl, const char *name, FILE *fp); void gpgsm_p12_export (ctrl_t ctrl, const char *name, estream_t stream);
/*-- delete.c --*/ /*-- delete.c --*/
int gpgsm_delete (ctrl_t ctrl, strlist_t names); int gpgsm_delete (ctrl_t ctrl, strlist_t names);
@ -406,11 +406,15 @@ gpg_error_t gpgsm_agent_send_nop (ctrl_t ctrl);
gpg_error_t gpgsm_agent_keyinfo (ctrl_t ctrl, const char *hexkeygrip, gpg_error_t gpgsm_agent_keyinfo (ctrl_t ctrl, const char *hexkeygrip,
char **r_serialno); char **r_serialno);
gpg_error_t gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, gpg_error_t gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg,
char **r_passphrase); int repeat, char **r_passphrase);
gpg_error_t gpgsm_agent_keywrap_key (ctrl_t ctrl, int forexport, gpg_error_t gpgsm_agent_keywrap_key (ctrl_t ctrl, int forexport,
void **r_kek, size_t *r_keklen); void **r_kek, size_t *r_keklen);
gpg_error_t gpgsm_agent_import_key (ctrl_t ctrl, gpg_error_t gpgsm_agent_import_key (ctrl_t ctrl,
const void *key, size_t keylen); const void *key, size_t keylen);
gpg_error_t gpgsm_agent_export_key (ctrl_t ctrl, const char *keygrip,
const char *desc,
unsigned char **r_result,
size_t *r_resultlen);
/*-- call-dirmngr.c --*/ /*-- call-dirmngr.c --*/
int gpgsm_dirmngr_isvalid (ctrl_t ctrl, int gpgsm_dirmngr_isvalid (ctrl_t ctrl,

View File

@ -759,8 +759,9 @@ parse_p12 (ctrl_t ctrl, ksba_reader_t reader, struct stats_s *stats)
err = gpgsm_agent_ask_passphrase err = gpgsm_agent_ask_passphrase
(ctrl, _("Please enter the passphrase to unprotect the PKCS#12 object."), (ctrl,
&passphrase); i18n_utf8 ("Please enter the passphrase to unprotect the PKCS#12 object."),
0, &passphrase);
if (err) if (err)
goto leave; goto leave;
@ -812,7 +813,7 @@ parse_p12 (ctrl_t ctrl, ksba_reader_t reader, struct stats_s *stats)
kparms = NULL; kparms = NULL;
if (err) if (err)
{ {
log_error ("failed to created S-expression from key: %s\n", log_error ("failed to create S-expression from key: %s\n",
gpg_strerror (err)); gpg_strerror (err));
goto leave; goto leave;
} }
@ -828,7 +829,7 @@ parse_p12 (ctrl_t ctrl, ksba_reader_t reader, struct stats_s *stats)
/* Convert to canonical encoding using a function which pads it to a /* Convert to canonical encoding using a function which pads it to a
multiple of 64 bits. We need this padding for AESWRAP. */ multiple of 64 bits. We need this padding for AESWRAP. */
err = make_canon_sexp_pad (s_key, &key, &keylen); err = make_canon_sexp_pad (s_key, 1, &key, &keylen);
if (err) if (err)
{ {
log_error ("error creating canonical S-expression\n"); log_error ("error creating canonical S-expression\n");

View File

@ -2024,7 +2024,7 @@ build_cert_bag (unsigned char *buffer, size_t buflen, char *salt,
static unsigned char * static unsigned char *
build_cert_sequence (unsigned char *buffer, size_t buflen, build_cert_sequence (const unsigned char *buffer, size_t buflen,
const unsigned char *sha1hash, const char *keyidstr, const unsigned char *sha1hash, const char *keyidstr,
size_t *r_length) size_t *r_length)
{ {
@ -2144,7 +2144,7 @@ build_cert_sequence (unsigned char *buffer, size_t buflen,
in R_LENGTH; return NULL in case of an error. If CHARSET is not in R_LENGTH; return NULL in case of an error. If CHARSET is not
NULL, re-encode PW to that character set. */ NULL, re-encode PW to that character set. */
unsigned char * unsigned char *
p12_build (gcry_mpi_t *kparms, unsigned char *cert, size_t certlen, p12_build (gcry_mpi_t *kparms, const void *cert, size_t certlen,
const char *pw, const char *charset, size_t *r_length) const char *pw, const char *charset, size_t *r_length)
{ {
unsigned char *buffer = NULL; unsigned char *buffer = NULL;
@ -2298,6 +2298,7 @@ main (int argc, char **argv)
unsigned char *buf; unsigned char *buf;
size_t buflen; size_t buflen;
gcry_mpi_t *result; gcry_mpi_t *result;
int badpass;
if (argc != 3) if (argc != 3)
{ {
@ -2330,7 +2331,7 @@ main (int argc, char **argv)
} }
fclose (fp); fclose (fp);
result = p12_parse (buf, buflen, argv[2], cert_cb, NULL); result = p12_parse (buf, buflen, argv[2], cert_cb, NULL, &badpass);
if (result) if (result)
{ {
int i, rc; int i, rc;

View File

@ -28,7 +28,7 @@ gcry_mpi_t *p12_parse (const unsigned char *buffer, size_t length,
void *certcbarg, int *r_badpass); void *certcbarg, int *r_badpass);
unsigned char *p12_build (gcry_mpi_t *kparms, unsigned char *p12_build (gcry_mpi_t *kparms,
unsigned char *cert, size_t certlen, const void *cert, size_t certlen,
const char *pw, const char *charset, const char *pw, const char *charset,
size_t *r_length); size_t *r_length);