mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
* minip12.c (parse_bag_encrypted_data): Finished implementation.
(p12_parse): Add callback args. * protect-tool.c (import_p12_cert_cb): New. (import_p12_file): Use it.
This commit is contained in:
parent
cfb33014ae
commit
a1dd1cc223
@ -1,3 +1,15 @@
|
||||
2004-02-10 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* minip12.c (parse_bag_encrypted_data): Finished implementation.
|
||||
(p12_parse): Add callback args.
|
||||
* protect-tool.c (import_p12_cert_cb): New.
|
||||
(import_p12_file): Use it.
|
||||
|
||||
2004-02-06 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* minip12.c (crypt_block): Add arg CIPHER_ALGO; changed all callers.
|
||||
(set_key_iv): Add arg KEYBYTES; changed caller.
|
||||
|
||||
2004-02-03 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* findkey.c (agent_key_from_file): Extra paranoid wipe.
|
||||
|
199
agent/minip12.c
199
agent/minip12.c
@ -1,5 +1,5 @@
|
||||
/* minip12.c - A minimal pkcs-12 implementation.
|
||||
* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -27,7 +27,12 @@
|
||||
#include <assert.h>
|
||||
#include <gcrypt.h>
|
||||
|
||||
#undef TEST
|
||||
#ifdef __GCC__
|
||||
#warning Remove this kludge and set the libgcrypt required version higher.
|
||||
#endif
|
||||
#ifndef GCRY_CIPHER_RFC2268_40
|
||||
#define GCRY_CIPHER_RFC2268_40 307
|
||||
#endif
|
||||
|
||||
#ifdef TEST
|
||||
#include <sys/stat.h>
|
||||
@ -97,6 +102,9 @@ 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 };
|
||||
@ -303,14 +311,16 @@ string_to_key (int id, char *salt, int iter, const char *pw,
|
||||
|
||||
|
||||
static int
|
||||
set_key_iv (gcry_cipher_hd_t chd, char *salt, int iter, const char *pw)
|
||||
set_key_iv (gcry_cipher_hd_t chd, char *salt, int iter, const char *pw,
|
||||
int keybytes)
|
||||
{
|
||||
unsigned char keybuf[24];
|
||||
int rc;
|
||||
|
||||
if (string_to_key (1, salt, iter, pw, 24, keybuf))
|
||||
assert (keybytes == 5 || keybytes == 24);
|
||||
if (string_to_key (1, salt, iter, pw, keybytes, keybuf))
|
||||
return -1;
|
||||
rc = gcry_cipher_setkey (chd, keybuf, 24);
|
||||
rc = gcry_cipher_setkey (chd, keybuf, keybytes);
|
||||
if (rc)
|
||||
{
|
||||
log_error ( "gcry_cipher_setkey failed: %s\n", gpg_strerror (rc));
|
||||
@ -331,18 +341,19 @@ set_key_iv (gcry_cipher_hd_t chd, char *salt, int iter, const char *pw)
|
||||
|
||||
static void
|
||||
crypt_block (unsigned char *buffer, size_t length, char *salt, int iter,
|
||||
const char *pw, int encrypt)
|
||||
const char *pw, int cipher_algo, int encrypt)
|
||||
{
|
||||
gcry_cipher_hd_t chd;
|
||||
int rc;
|
||||
|
||||
rc = gcry_cipher_open (&chd, GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC, 0);
|
||||
rc = gcry_cipher_open (&chd, cipher_algo, GCRY_CIPHER_MODE_CBC, 0);
|
||||
if (rc)
|
||||
{
|
||||
log_error ( "gcry_cipher_open failed: %s\n", gpg_strerror(-1));
|
||||
log_error ( "gcry_cipher_open failed: %s\n", gpg_strerror(rc));
|
||||
return;
|
||||
}
|
||||
if (set_key_iv (chd, salt, iter, pw))
|
||||
if (set_key_iv (chd, salt, iter, pw,
|
||||
cipher_algo == GCRY_CIPHER_RFC2268_40? 5:24))
|
||||
goto leave;
|
||||
|
||||
rc = encrypt? gcry_cipher_encrypt (chd, buffer, length, NULL, 0)
|
||||
@ -354,12 +365,6 @@ crypt_block (unsigned char *buffer, size_t length, char *salt, int iter,
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* { */
|
||||
/* FILE *fp = fopen("inner.der", "wb"); */
|
||||
/* fwrite (buffer, 1, length, fp); */
|
||||
/* fclose (fp); */
|
||||
/* } */
|
||||
|
||||
leave:
|
||||
gcry_cipher_close (chd);
|
||||
}
|
||||
@ -369,12 +374,18 @@ crypt_block (unsigned char *buffer, size_t length, char *salt, int iter,
|
||||
|
||||
static int
|
||||
parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
|
||||
int startoffset)
|
||||
int startoffset, const char *pw,
|
||||
void (*certcb)(void*, const unsigned char*, size_t),
|
||||
void *certcbarg)
|
||||
{
|
||||
struct tag_info ti;
|
||||
const unsigned char *p = buffer;
|
||||
size_t n = length;
|
||||
const char *where;
|
||||
char salt[8];
|
||||
unsigned int iter;
|
||||
unsigned char *plain = NULL;
|
||||
|
||||
|
||||
where = "start";
|
||||
if (parse_tag (&p, &n, &ti))
|
||||
@ -406,18 +417,17 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
|
||||
p += DIM(oid_data);
|
||||
n -= DIM(oid_data);
|
||||
|
||||
#if 0
|
||||
where = "bag.encryptedData.keyinfo"
|
||||
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
|
||||
if (!ti.class && ti.tag == TAG_OBJECT_ID
|
||||
&& ti.length == DIM(oid_pbeWithSHAAnd40BitRC2_CBC)
|
||||
&& memcmp (p, oid_pbeWithSHAAnd40BitRC2_CBC,
|
||||
DIM(oid_pbeWithSHAAnd40BitRC2_CBC)))
|
||||
&& !memcmp (p, oid_pbeWithSHAAnd40BitRC2_CBC,
|
||||
DIM(oid_pbeWithSHAAnd40BitRC2_CBC)))
|
||||
{
|
||||
p += DIM(oid_pbeWithSHAAnd40BitRC2_CBC);
|
||||
n -= DIM(oid_pbeWithSHAAnd40BitRC2_CBC);
|
||||
@ -451,16 +461,118 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
|
||||
where = "rc2-ciphertext";
|
||||
if (parse_tag (&p, &n, &ti))
|
||||
goto bailout;
|
||||
if (ti.class || ti.tag != TAG_OCTET_STRING || !ti.length )
|
||||
if (ti.class != CONTEXT || ti.tag != 0 || !ti.length )
|
||||
goto bailout;
|
||||
|
||||
log_info ("%lu bytes of RC2 encrypted text\n", ti.length);
|
||||
#endif
|
||||
|
||||
plain = gcry_malloc_secure (ti.length);
|
||||
if (!plain)
|
||||
{
|
||||
log_error ("error allocating decryption buffer\n");
|
||||
goto bailout;
|
||||
}
|
||||
memcpy (plain, p, ti.length);
|
||||
crypt_block (plain, ti.length, salt, iter, pw, GCRY_CIPHER_RFC2268_40, 0);
|
||||
n = ti.length;
|
||||
startoffset = 0;
|
||||
buffer = p = plain;
|
||||
|
||||
where = "outer.outer.seq";
|
||||
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;
|
||||
|
||||
/* Loop over all certificates inside the bab. */
|
||||
while (n)
|
||||
{
|
||||
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
|
||||
|| ti.length != DIM(oid_pkcs_12_CertBag)
|
||||
|| memcmp (p, oid_pkcs_12_CertBag,
|
||||
DIM(oid_pkcs_12_CertBag)))
|
||||
goto bailout;
|
||||
p += DIM(oid_pkcs_12_CertBag);
|
||||
n -= DIM(oid_pkcs_12_CertBag);
|
||||
|
||||
where = "certbag.before.certheader";
|
||||
if (parse_tag (&p, &n, &ti))
|
||||
goto bailout;
|
||||
if (ti.class != CONTEXT || 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_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 != CONTEXT || 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 a rest of
|
||||
sie les than the cipher's block length. */
|
||||
if (n < 8)
|
||||
n = 0;
|
||||
|
||||
/* Skip the optional SET with the pkcs12 cert attributes. */
|
||||
if (n)
|
||||
{
|
||||
where = "certbag.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;
|
||||
}
|
||||
}
|
||||
|
||||
gcry_free (plain);
|
||||
|
||||
return 0;
|
||||
bailout:
|
||||
gcry_free (plain);
|
||||
log_error ("encryptedData error at \"%s\", offset %u\n",
|
||||
where, (p - buffer)+startoffset);
|
||||
return -1;
|
||||
@ -574,7 +686,7 @@ parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
|
||||
goto bailout;
|
||||
}
|
||||
memcpy (plain, p, ti.length);
|
||||
crypt_block (plain, ti.length, salt, iter, pw, 0);
|
||||
crypt_block (plain, ti.length, salt, iter, pw, GCRY_CIPHER_3DES, 0);
|
||||
n = ti.length;
|
||||
startoffset = 0;
|
||||
buffer = p = plain;
|
||||
@ -673,9 +785,12 @@ parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
|
||||
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. */
|
||||
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)
|
||||
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;
|
||||
@ -751,7 +866,8 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw)
|
||||
n -= DIM(oid_encryptedData);
|
||||
len -= DIM(oid_encryptedData);
|
||||
where = "bag.encryptedData";
|
||||
if (parse_bag_encrypted_data (p, n, (p - buffer)))
|
||||
if (parse_bag_encrypted_data (p, n, (p - buffer), pw,
|
||||
certcb, certcbarg))
|
||||
goto bailout;
|
||||
}
|
||||
else if (ti.tag == TAG_OBJECT_ID && ti.length == DIM(oid_data)
|
||||
@ -1034,7 +1150,7 @@ p12_build (gcry_mpi_t *kparms, const char *pw, size_t *r_length)
|
||||
|
||||
/* Encrypt it and prepend a lot of stupid things. */
|
||||
gcry_randomize (salt, 8, GCRY_STRONG_RANDOM);
|
||||
crypt_block (plain, plainlen, salt, 1024, pw, 1);
|
||||
crypt_block (plain, plainlen, salt, 1024, pw, GCRY_CIPHER_3DES, 1);
|
||||
/* the data goes into an octet string. */
|
||||
needed = compute_tag_length (plainlen);
|
||||
needed += plainlen;
|
||||
@ -1128,14 +1244,21 @@ p12_build (gcry_mpi_t *kparms, const char *pw, size_t *r_length)
|
||||
|
||||
|
||||
#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;
|
||||
char *buf;
|
||||
unsigned char *buf;
|
||||
size_t buflen;
|
||||
GcryMPI *result;
|
||||
gcry_mpi_t *result;
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
@ -1168,23 +1291,23 @@ main (int argc, char **argv)
|
||||
}
|
||||
fclose (fp);
|
||||
|
||||
result = p12_parse (buf, buflen, argv[2]);
|
||||
result = p12_parse (buf, buflen, argv[2], cert_cb, NULL);
|
||||
if (result)
|
||||
{
|
||||
int i, rc;
|
||||
char *buf;
|
||||
unsigned char *tmpbuf;
|
||||
|
||||
for (i=0; result[i]; i++)
|
||||
{
|
||||
rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, (void**)&buf,
|
||||
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, buf);
|
||||
gcry_free (buf);
|
||||
printf ("%d: %s\n", i, tmpbuf);
|
||||
gcry_free (tmpbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1192,4 +1315,10 @@ main (int argc, char **argv)
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
compile-command: "gcc -Wall -O -g -DTEST=1 -o minip12 minip12.c ../jnlib/libjnlib.a -L /usr/local/lib -lgcrypt -lgpg-error"
|
||||
End:
|
||||
*/
|
||||
#endif /* TEST */
|
||||
|
@ -24,7 +24,9 @@
|
||||
#include <gcrypt.h>
|
||||
|
||||
gcry_mpi_t *p12_parse (const unsigned char *buffer, size_t length,
|
||||
const char *pw);
|
||||
const char *pw,
|
||||
void (*certcb)(void*, const unsigned char*, size_t),
|
||||
void *certcbarg);
|
||||
|
||||
unsigned char *p12_build (gcry_mpi_t *kparms, const char *pw,
|
||||
size_t *r_length);
|
||||
|
@ -563,6 +563,23 @@ rsa_key_check (struct rsa_secret_key_s *skey)
|
||||
}
|
||||
|
||||
|
||||
/* 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)
|
||||
{
|
||||
struct b64state state;
|
||||
gpg_error_t err, err2;
|
||||
|
||||
err = b64enc_start (&state, stdout, "CERTIFICATE");
|
||||
if (!err)
|
||||
err = b64enc_write (&state, cert, certlen);
|
||||
err2 = b64enc_finish (&state);
|
||||
if (!err)
|
||||
err = err2;
|
||||
if (err)
|
||||
log_error ("error writing armored certificate: %s\n", gpg_strerror (err));
|
||||
}
|
||||
|
||||
static void
|
||||
import_p12_file (const char *fname)
|
||||
{
|
||||
@ -583,11 +600,12 @@ import_p12_file (const char *fname)
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
kparms = p12_parse (buf, buflen, get_passphrase ());
|
||||
kparms = p12_parse (buf, buflen, get_passphrase (),
|
||||
import_p12_cert_cb, NULL);
|
||||
xfree (buf);
|
||||
if (!kparms)
|
||||
{
|
||||
log_error ("error parsing or decrypting the PKCS-1 file\n");
|
||||
log_error ("error parsing or decrypting the PKCS-12 file\n");
|
||||
return;
|
||||
}
|
||||
for (i=0; kparms[i]; i++)
|
||||
|
Loading…
x
Reference in New Issue
Block a user