mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-02 12:01:32 +01:00
Support pkcs#12 import of PBES2 encoded data.
This is so that we read compatible with gnutls's certtool. Only AES-128 is supported. The latest Libgcrypt from git is required. Fixes bug#1321.
This commit is contained in:
parent
87a6a1c3fe
commit
35c731d889
@ -1,3 +1,12 @@
|
||||
2011-03-10 Werner Koch <wk@g10code.com>
|
||||
|
||||
* minip12.c (oid_pkcs5PBKDF2, oid_pkcs5PBES2, oid_aes128_CBC): New.
|
||||
(set_key_iv_pbes2): New.
|
||||
(crypt_block): Add args IV and IVLEN. Call set_key_iv_pbes2.
|
||||
(decrypt_block): Add args IV and IVLEN.
|
||||
(parse_bag_encrypted_data): Hack to support PBES2 data.
|
||||
(parse_bag_data): Ditto.
|
||||
|
||||
2011-03-03 Werner Koch <wk@g10code.com>
|
||||
|
||||
* base64.c (base64_finish_write): Do not copy to radbuf to get rid
|
||||
|
260
sm/minip12.c
260
sm/minip12.c
@ -1,5 +1,5 @@
|
||||
/* minip12.c - A minimal pkcs-12 implementation.
|
||||
* Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2002, 2003, 2004, 2006, 2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -104,6 +104,12 @@ static unsigned char const oid_pbeWithSHAAnd40BitRC2_CBC[10] = {
|
||||
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_pkcs5PBKDF2[9] = {
|
||||
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0C };
|
||||
static unsigned char const oid_pkcs5PBES2[9] = {
|
||||
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0D };
|
||||
static unsigned char const oid_aes128_CBC[9] = {
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02 };
|
||||
|
||||
static unsigned char const oid_rsaEncryption[9] = {
|
||||
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };
|
||||
@ -447,9 +453,54 @@ set_key_iv (gcry_cipher_hd_t chd, char *salt, size_t saltlen, int iter,
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
set_key_iv_pbes2 (gcry_cipher_hd_t chd, char *salt, size_t saltlen, int iter,
|
||||
const void *iv, size_t ivlen, const char *pw, int algo)
|
||||
{
|
||||
unsigned char *keybuf;
|
||||
size_t keylen;
|
||||
int rc;
|
||||
|
||||
keylen = gcry_cipher_get_algo_keylen (algo);
|
||||
if (!keylen)
|
||||
return -1;
|
||||
keybuf = gcry_malloc_secure (keylen);
|
||||
if (!keybuf)
|
||||
return -1;
|
||||
|
||||
rc = gcry_kdf_derive (pw, strlen (pw),
|
||||
GCRY_KDF_PBKDF2, GCRY_MD_SHA1,
|
||||
salt, saltlen, iter, keylen, keybuf);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("gcry_kdf_derive failed: %s\n", gpg_strerror (rc));
|
||||
gcry_free (keybuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = gcry_cipher_setkey (chd, keybuf, keylen);
|
||||
gcry_free (keybuf);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("gcry_cipher_setkey failed: %s\n", gpg_strerror (rc));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
rc = gcry_cipher_setiv (chd, iv, ivlen);
|
||||
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)
|
||||
int iter, const void *iv, size_t ivlen,
|
||||
const char *pw, int cipher_algo, int encrypt)
|
||||
{
|
||||
gcry_cipher_hd_t chd;
|
||||
int rc;
|
||||
@ -461,7 +512,10 @@ crypt_block (unsigned char *buffer, size_t length, char *salt, size_t saltlen,
|
||||
wipememory (buffer, length);
|
||||
return;
|
||||
}
|
||||
if (set_key_iv (chd, salt, saltlen, iter, pw,
|
||||
|
||||
if (cipher_algo == GCRY_CIPHER_AES128
|
||||
? set_key_iv_pbes2 (chd, salt, saltlen, iter, iv, ivlen, pw, cipher_algo)
|
||||
: set_key_iv (chd, salt, saltlen, iter, pw,
|
||||
cipher_algo == GCRY_CIPHER_RFC2268_40? 5:24))
|
||||
{
|
||||
wipememory (buffer, length);
|
||||
@ -495,7 +549,8 @@ crypt_block (unsigned char *buffer, size_t length, char *salt, size_t saltlen,
|
||||
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 iter, const void *iv, size_t ivlen,
|
||||
const char *pw, int cipher_algo,
|
||||
int (*check_fnc) (const void *, size_t))
|
||||
{
|
||||
static const char * const charsets[] = {
|
||||
@ -566,7 +621,7 @@ decrypt_block (const void *ciphertext, unsigned char *plaintext, size_t length,
|
||||
charsets[charsetidx]);
|
||||
}
|
||||
memcpy (plaintext, ciphertext, length);
|
||||
crypt_block (plaintext, length, salt, saltlen, iter,
|
||||
crypt_block (plaintext, length, salt, saltlen, iter, iv, ivlen,
|
||||
convertedpw? convertedpw:pw, cipher_algo, 0);
|
||||
if (check_fnc (plaintext, length))
|
||||
break; /* Decryption succeeded. */
|
||||
@ -618,12 +673,14 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
|
||||
const char *where;
|
||||
char salt[20];
|
||||
size_t saltlen;
|
||||
char iv[16];
|
||||
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;
|
||||
int is_pbes2 = 0;
|
||||
gcry_mpi_t *result = NULL;
|
||||
int result_count;
|
||||
|
||||
@ -683,9 +740,84 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
|
||||
n -= DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC);
|
||||
is_3des = 1;
|
||||
}
|
||||
else if (!ti.class && ti.tag == TAG_OBJECT_ID
|
||||
&& ti.length == DIM(oid_pkcs5PBES2)
|
||||
&& !memcmp (p, oid_pkcs5PBES2, ti.length))
|
||||
{
|
||||
p += ti.length;
|
||||
n -= ti.length;
|
||||
is_pbes2 = 1;
|
||||
}
|
||||
else
|
||||
goto bailout;
|
||||
|
||||
if (is_pbes2)
|
||||
{
|
||||
where = "pkcs5PBES2-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_SEQUENCE)
|
||||
goto bailout;
|
||||
if (parse_tag (&p, &n, &ti))
|
||||
goto bailout;
|
||||
if (!(!ti.class && ti.tag == TAG_OBJECT_ID
|
||||
&& ti.length == DIM(oid_pkcs5PBKDF2)
|
||||
&& !memcmp (p, oid_pkcs5PBKDF2, ti.length)))
|
||||
goto bailout; /* Not PBKDF2. */
|
||||
p += ti.length;
|
||||
n -= ti.length;
|
||||
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 < sizeof salt))
|
||||
goto bailout; /* No salt or unsupported length. */
|
||||
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; /* No valid iteration count. */
|
||||
for (iter=0; ti.length; ti.length--)
|
||||
{
|
||||
iter <<= 8;
|
||||
iter |= (*p++) & 0xff;
|
||||
n--;
|
||||
}
|
||||
/* Note: We don't support the optional parameters but assume
|
||||
that the algorithmIdentifier follows. */
|
||||
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_aes128_CBC)
|
||||
&& !memcmp (p, oid_aes128_CBC, ti.length)))
|
||||
goto bailout; /* Not AES-128. */
|
||||
p += ti.length;
|
||||
n -= ti.length;
|
||||
if (parse_tag (&p, &n, &ti))
|
||||
goto bailout;
|
||||
if (!(!ti.class && ti.tag == TAG_OCTET_STRING && ti.length == sizeof iv))
|
||||
goto bailout; /* Bad IV. */
|
||||
memcpy (iv, p, sizeof iv);
|
||||
p += sizeof iv;
|
||||
n -= sizeof iv;
|
||||
}
|
||||
else
|
||||
{
|
||||
where = "rc2or3des-params";
|
||||
if (parse_tag (&p, &n, &ti))
|
||||
goto bailout;
|
||||
@ -710,8 +842,9 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
|
||||
iter |= (*p++) & 0xff;
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
where = "rc2or3des-ciphertext";
|
||||
where = "rc2or3desoraes-ciphertext";
|
||||
if (parse_tag (&p, &n, &ti))
|
||||
goto bailout;
|
||||
|
||||
@ -735,7 +868,8 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
|
||||
else
|
||||
goto bailout;
|
||||
|
||||
log_info ("%lu bytes of %s encrypted text\n",ti.length,is_3des?"3DES":"RC2");
|
||||
log_info ("%lu bytes of %s encrypted text\n",ti.length,
|
||||
is_pbes2?"AES128":is_3des?"3DES":"RC2");
|
||||
|
||||
plain = gcry_malloc_secure (ti.length);
|
||||
if (!plain)
|
||||
@ -743,7 +877,9 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
|
||||
log_error ("error allocating decryption buffer\n");
|
||||
goto bailout;
|
||||
}
|
||||
decrypt_block (p, plain, ti.length, salt, saltlen, iter, pw,
|
||||
decrypt_block (p, plain, ti.length, salt, saltlen, iter,
|
||||
iv, is_pbes2?16:0, pw,
|
||||
is_pbes2 ? GCRY_CIPHER_AES128 :
|
||||
is_3des ? GCRY_CIPHER_3DES : GCRY_CIPHER_RFC2268_40,
|
||||
bag_decrypted_data_p);
|
||||
n = ti.length;
|
||||
@ -950,7 +1086,7 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
|
||||
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)
|
||||
if (n <= (is_pbes2? 16:8))
|
||||
n = 0;
|
||||
|
||||
/* Skip the optional SET with the pkcs12 cert attributes. */
|
||||
@ -965,7 +1101,7 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
|
||||
{ /* The optional SET. */
|
||||
p += ti.length;
|
||||
n -= ti.length;
|
||||
if (n <= 8)
|
||||
if (n <= (is_pbes2?16:8))
|
||||
n = 0;
|
||||
if (n && parse_tag (&p, &n, &ti))
|
||||
goto bailout;
|
||||
@ -1049,6 +1185,7 @@ parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
|
||||
const char *where;
|
||||
char salt[20];
|
||||
size_t saltlen;
|
||||
char iv[16];
|
||||
unsigned int iter;
|
||||
int len;
|
||||
unsigned char *plain = NULL;
|
||||
@ -1056,6 +1193,7 @@ parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
|
||||
int result_count, i;
|
||||
unsigned char *cram_buffer = NULL;
|
||||
size_t consumed = 0; /* Number of bytes consumed from the orginal buffer. */
|
||||
int is_pbes2 = 0;
|
||||
|
||||
where = "start";
|
||||
if (parse_tag (&p, &n, &ti))
|
||||
@ -1119,14 +1257,92 @@ parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
|
||||
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,
|
||||
if (ti.class == 0 && 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);
|
||||
}
|
||||
else if (ti.class == 0 && ti.tag == TAG_OBJECT_ID
|
||||
&& ti.length == DIM(oid_pkcs5PBES2)
|
||||
&& !memcmp (p, oid_pkcs5PBES2, DIM(oid_pkcs5PBES2)))
|
||||
{
|
||||
p += DIM(oid_pkcs5PBES2);
|
||||
n -= DIM(oid_pkcs5PBES2);
|
||||
is_pbes2 = 1;
|
||||
}
|
||||
else
|
||||
goto bailout;
|
||||
|
||||
if (is_pbes2)
|
||||
{
|
||||
where = "pkcs5PBES2-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_SEQUENCE)
|
||||
goto bailout;
|
||||
if (parse_tag (&p, &n, &ti))
|
||||
goto bailout;
|
||||
if (!(!ti.class && ti.tag == TAG_OBJECT_ID
|
||||
&& ti.length == DIM(oid_pkcs5PBKDF2)
|
||||
&& !memcmp (p, oid_pkcs5PBKDF2, ti.length)))
|
||||
goto bailout; /* Not PBKDF2. */
|
||||
p += ti.length;
|
||||
n -= ti.length;
|
||||
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 < sizeof salt))
|
||||
goto bailout; /* No salt or unsupported length. */
|
||||
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; /* No valid iteration count. */
|
||||
for (iter=0; ti.length; ti.length--)
|
||||
{
|
||||
iter <<= 8;
|
||||
iter |= (*p++) & 0xff;
|
||||
n--;
|
||||
}
|
||||
/* Note: We don't support the optional parameters but assume
|
||||
that the algorithmIdentifier follows. */
|
||||
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_aes128_CBC)
|
||||
&& !memcmp (p, oid_aes128_CBC, ti.length)))
|
||||
goto bailout; /* Not AES-128. */
|
||||
p += ti.length;
|
||||
n -= ti.length;
|
||||
if (parse_tag (&p, &n, &ti))
|
||||
goto bailout;
|
||||
if (!(!ti.class && ti.tag == TAG_OCTET_STRING && ti.length == sizeof iv))
|
||||
goto bailout; /* Bad IV. */
|
||||
memcpy (iv, p, sizeof iv);
|
||||
p += sizeof iv;
|
||||
n -= sizeof iv;
|
||||
}
|
||||
else
|
||||
{
|
||||
where = "3des-params";
|
||||
if (parse_tag (&p, &n, &ti))
|
||||
goto bailout;
|
||||
@ -1151,14 +1367,16 @@ parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
|
||||
iter |= (*p++) & 0xff;
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
where = "3des-ciphertext";
|
||||
where = "3desoraes-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);
|
||||
log_info ("%lu bytes of %s encrypted text\n",
|
||||
ti.length, is_pbes2? "AES128":"3DES");
|
||||
|
||||
plain = gcry_malloc_secure (ti.length);
|
||||
if (!plain)
|
||||
@ -1167,8 +1385,9 @@ parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
|
||||
goto bailout;
|
||||
}
|
||||
consumed += p - p_start + ti.length;
|
||||
decrypt_block (p, plain, ti.length, salt, saltlen, iter, pw,
|
||||
GCRY_CIPHER_3DES,
|
||||
decrypt_block (p, plain, ti.length, salt, saltlen, iter,
|
||||
iv, is_pbes2? 16:0, pw,
|
||||
is_pbes2? GCRY_CIPHER_AES128 : GCRY_CIPHER_3DES,
|
||||
bag_data_p);
|
||||
n = ti.length;
|
||||
startoffset = 0;
|
||||
@ -2223,7 +2442,7 @@ p12_build (gcry_mpi_t *kparms, const void *cert, size_t certlen,
|
||||
|
||||
/* Encrypt it. */
|
||||
gcry_randomize (salt, 8, GCRY_STRONG_RANDOM);
|
||||
crypt_block (buffer, buflen, salt, 8, 2048, pw,
|
||||
crypt_block (buffer, buflen, salt, 8, 2048, NULL, 0, pw,
|
||||
GCRY_CIPHER_RFC2268_40, 1);
|
||||
|
||||
/* Encode the encrypted stuff into a bag. */
|
||||
@ -2246,7 +2465,8 @@ p12_build (gcry_mpi_t *kparms, const void *cert, size_t certlen,
|
||||
|
||||
/* Encrypt it. */
|
||||
gcry_randomize (salt, 8, GCRY_STRONG_RANDOM);
|
||||
crypt_block (buffer, buflen, salt, 8, 2048, pw, GCRY_CIPHER_3DES, 1);
|
||||
crypt_block (buffer, buflen, salt, 8, 2048, NULL, 0,
|
||||
pw, GCRY_CIPHER_3DES, 1);
|
||||
|
||||
/* Encode the encrypted stuff into a bag. */
|
||||
if (cert && certlen)
|
||||
|
Loading…
x
Reference in New Issue
Block a user