Support import from TrustedMIME (i.e. from simple keyBags)

This commit is contained in:
Werner Koch 2006-07-21 09:41:11 +00:00
parent 4954c5f1c3
commit d035d2a52e
4 changed files with 203 additions and 47 deletions

2
NEWS
View File

@ -2,6 +2,8 @@ Noteworthy changes in version 1.9.22
------------------------------------------------- -------------------------------------------------
* Enhanced pkcs#12 support to allow import from simple keyBags.
Noteworthy changes in version 1.9.21 (2006-06-20) Noteworthy changes in version 1.9.21 (2006-06-20)
------------------------------------------------- -------------------------------------------------

View File

@ -1,3 +1,10 @@
2006-07-21 Werner Koch <wk@g10code.com>
* minip12.c (oid_pkcs_12_keyBag): New.
(parse_bag_encrypted_data): New arg R_RESULT. Support keybags and
return the key object.
(p12_parse): Take new arg into account. Free RESULT on error.
2006-06-26 Werner Koch <wk@g10code.com> 2006-06-26 Werner Koch <wk@g10code.com>
* gpg-agent.c (handle_signal): Print infor for SIGUSR2 only in * gpg-agent.c (handle_signal): Print infor for SIGUSR2 only in

View File

@ -88,6 +88,8 @@ static unsigned char const oid_data[9] = {
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 }; 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 };
static unsigned char const oid_encryptedData[9] = { static unsigned char const oid_encryptedData[9] = {
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x06 }; 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] = { static unsigned char const oid_pkcs_12_pkcs_8ShroudedKeyBag[11] = {
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x0A, 0x01, 0x02 }; 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x0A, 0x01, 0x02 };
static unsigned char const oid_pkcs_12_CertBag[11] = { static unsigned char const oid_pkcs_12_CertBag[11] = {
@ -465,11 +467,13 @@ crypt_block (unsigned char *buffer, size_t length, char *salt, size_t saltlen,
/* 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 static int
parse_bag_encrypted_data (const unsigned char *buffer, size_t length, parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
int startoffset, size_t *r_consumed, const char *pw, int startoffset, size_t *r_consumed, const char *pw,
void (*certcb)(void*, const unsigned char*, size_t), void (*certcb)(void*, const unsigned char*, size_t),
void *certcbarg) void *certcbarg, gcry_mpi_t **r_result)
{ {
struct tag_info ti; struct tag_info ti;
const unsigned char *p = buffer; const unsigned char *p = buffer;
@ -483,7 +487,12 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
int bad_pass = 0; int bad_pass = 0;
unsigned char *cram_buffer = NULL; unsigned char *cram_buffer = NULL;
size_t consumed = 0; /* Number of bytes consumed from the orginal buffer. */ 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"; where = "start";
if (parse_tag (&p, &n, &ti)) if (parse_tag (&p, &n, &ti))
goto bailout; goto bailout;
@ -529,10 +538,19 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
p += DIM(oid_pbeWithSHAAnd40BitRC2_CBC); p += DIM(oid_pbeWithSHAAnd40BitRC2_CBC);
n -= 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 else
goto bailout; goto bailout;
where = "rc2-params"; where = "rc2or3des-params";
if (parse_tag (&p, &n, &ti)) if (parse_tag (&p, &n, &ti))
goto bailout; goto bailout;
if (ti.class || ti.tag != TAG_SEQUENCE) if (ti.class || ti.tag != TAG_SEQUENCE)
@ -557,7 +575,7 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
n--; n--;
} }
where = "rc2-ciphertext"; where = "rc2or3des-ciphertext";
if (parse_tag (&p, &n, &ti)) if (parse_tag (&p, &n, &ti))
goto bailout; goto bailout;
@ -566,7 +584,7 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
{ {
/* Mozilla exported certs now come with single byte chunks of /* Mozilla exported certs now come with single byte chunks of
octect strings. (Mozilla Firefox 1.0.4). Arghh. */ octect strings. (Mozilla Firefox 1.0.4). Arghh. */
where = "cram-rc2-ciphertext"; where = "cram-rc2or3des-ciphertext";
cram_buffer = cram_octet_string ( p, &n, &consumed); cram_buffer = cram_octet_string ( p, &n, &consumed);
if (!cram_buffer) if (!cram_buffer)
goto bailout; goto bailout;
@ -581,7 +599,7 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
else else
goto bailout; goto bailout;
log_info ("%lu bytes of RC2 encrypted text\n", ti.length); log_info ("%lu bytes of %s encrypted text\n",ti.length,is_3des?"3DES":"RC2");
plain = gcry_malloc_secure (ti.length); plain = gcry_malloc_secure (ti.length);
if (!plain) if (!plain)
@ -591,7 +609,9 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
} }
memcpy (plain, p, ti.length); memcpy (plain, p, ti.length);
crypt_block (plain, ti.length, salt, saltlen, crypt_block (plain, ti.length, salt, saltlen,
iter, pw, GCRY_CIPHER_RFC2268_40, 0); iter, pw,
is_3des? GCRY_CIPHER_3DES : GCRY_CIPHER_RFC2268_40,
0);
n = ti.length; n = ti.length;
startoffset = 0; startoffset = 0;
p_start = p = plain; p_start = p = plain;
@ -625,7 +645,8 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
/* Loop over all certificates inside the bag. */ /* Loop over all certificates inside the bag. */
while (n) while (n)
{ {
int isbag = 0; int iscrlbag = 0;
int iskeybag = 0;
where = "certbag.nextcert"; where = "certbag.nextcert";
if (ti.class || ti.tag != TAG_SEQUENCE) if (ti.class || ti.tag != TAG_SEQUENCE)
@ -647,7 +668,17 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
{ {
p += DIM(oid_pkcs_12_CrlBag); p += DIM(oid_pkcs_12_CrlBag);
n -= DIM(oid_pkcs_12_CrlBag); n -= DIM(oid_pkcs_12_CrlBag);
isbag = 1; 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 else
goto bailout; goto bailout;
@ -657,14 +688,106 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
goto bailout; goto bailout;
if (ti.class != CONTEXT || ti.tag) if (ti.class != CONTEXT || ti.tag)
goto bailout; goto bailout;
if (isbag) if (iscrlbag)
{ {
log_info ("skipping unsupported crlBag\n"); log_info ("skipping unsupported crlBag\n");
p += ti.length; p += ti.length;
n -= 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 else
{ {
log_info ("processing certBag\n");
if (parse_tag (&p, &n, &ti)) if (parse_tag (&p, &n, &ti))
goto bailout; goto bailout;
if (ti.class || ti.tag != TAG_SEQUENCE) if (ti.class || ti.tag != TAG_SEQUENCE)
@ -730,9 +853,19 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
*r_consumed = consumed; *r_consumed = consumed;
gcry_free (plain); gcry_free (plain);
gcry_free (cram_buffer); gcry_free (cram_buffer);
if (r_result)
*r_result = result;
return 0; return 0;
bailout: bailout:
if (result)
{
int i;
for (i=0; result[i]; i++)
gcry_mpi_release (result[i]);
gcry_free (result);
}
if (r_consumed) if (r_consumed)
*r_consumed = consumed; *r_consumed = consumed;
gcry_free (plain); gcry_free (plain);
@ -1066,7 +1199,7 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
bagseqlength = ti.length; bagseqlength = ti.length;
while (bagseqlength || bagseqndef) while (bagseqlength || bagseqndef)
{ {
log_debug ( "at offset %u\n", (p - p_start)); /* log_debug ( "at offset %u\n", (p - p_start)); */
where = "bag-sequence"; where = "bag-sequence";
if (parse_tag (&p, &n, &ti)) if (parse_tag (&p, &n, &ti))
goto bailout; goto bailout;
@ -1105,7 +1238,8 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
len -= DIM(oid_encryptedData); len -= DIM(oid_encryptedData);
where = "bag.encryptedData"; where = "bag.encryptedData";
if (parse_bag_encrypted_data (p, n, (p - p_start), &consumed, pw, if (parse_bag_encrypted_data (p, n, (p - p_start), &consumed, pw,
certcb, certcbarg)) certcb, certcbarg,
result? NULL : &result))
goto bailout; goto bailout;
if (lenndef) if (lenndef)
len += consumed; len += consumed;
@ -1115,7 +1249,7 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
{ {
if (result) if (result)
{ {
log_info ("already got an data object, skipping next one\n"); log_info ("already got an key object, skipping this one\n");
p += ti.length; p += ti.length;
n -= ti.length; n -= ti.length;
} }
@ -1159,7 +1293,14 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
return result; return result;
bailout: bailout:
log_error ("error at \"%s\", offset %u\n", where, (p - p_start)); log_error ("error at \"%s\", offset %u\n", where, (p - p_start));
/* fixme: need to release RESULT. */ if (result)
{
int i;
for (i=0; result[i]; i++)
gcry_mpi_release (result[i]);
gcry_free (result);
}
gcry_free (cram_buffer); gcry_free (cram_buffer);
return NULL; return NULL;
} }
@ -1227,6 +1368,8 @@ create_final (struct buffer_s *sequences, const char *pw, size_t *r_length)
unsigned char keybuf[20]; unsigned char keybuf[20];
gcry_md_hd_t md; gcry_md_hd_t md;
int rc; int rc;
int with_mac = 1;
/* 9 steps to create the pkcs#12 Krampf. */ /* 9 steps to create the pkcs#12 Krampf. */
@ -1264,7 +1407,8 @@ create_final (struct buffer_s *sequences, const char *pw, size_t *r_length)
needed += 3; needed += 3;
/* 0. And the final outer sequence. */ /* 0. And the final outer sequence. */
needed += DIM (data_mactemplate); if (with_mac)
needed += DIM (data_mactemplate);
len[0] = needed; len[0] = needed;
n = compute_tag_length (needed); n = compute_tag_length (needed);
needed += n; needed += n;
@ -1311,37 +1455,40 @@ create_final (struct buffer_s *sequences, const char *pw, size_t *r_length)
p += sequences[i].length; p += sequences[i].length;
} }
/* Intermezzo to compute the MAC. */ if (with_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); /* Intermezzo to compute the MAC. */
return NULL; maclen = p - macstart;
} gcry_randomize (salt, 8, GCRY_STRONG_RANDOM);
rc = gcry_md_open (&md, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC); if (string_to_key (3, salt, 8, 2048, pw, 20, keybuf))
if (rc) {
{ gcry_free (result);
log_error ("gcry_md_open failed: %s\n", gpg_strerror (rc)); return NULL;
gcry_free (result); }
return NULL; rc = gcry_md_open (&md, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC);
} if (rc)
rc = gcry_md_setkey (md, keybuf, 20); {
if (rc) log_error ("gcry_md_open failed: %s\n", gpg_strerror (rc));
{ gcry_free (result);
log_error ("gcry_md_setkey failed: %s\n", gpg_strerror (rc)); return NULL;
gcry_md_close (md); }
gcry_free (result); rc = gcry_md_setkey (md, keybuf, 20);
return NULL; if (rc)
} {
gcry_md_write (md, macstart, maclen); 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. */ /* 8. Append the MAC template and fix it up. */
memcpy (p, data_mactemplate, DIM (data_mactemplate)); memcpy (p, data_mactemplate, DIM (data_mactemplate));
memcpy (p + DATA_MACTEMPLATE_SALT_OFF, salt, 8); memcpy (p + DATA_MACTEMPLATE_SALT_OFF, salt, 8);
memcpy (p + DATA_MACTEMPLATE_MAC_OFF, gcry_md_read (md, 0), 20); memcpy (p + DATA_MACTEMPLATE_MAC_OFF, gcry_md_read (md, 0), 20);
p += DIM (data_mactemplate); p += DIM (data_mactemplate);
gcry_md_close (md); gcry_md_close (md);
}
/* Ready. */ /* Ready. */
resultlen = p - result; resultlen = p - result;
@ -1952,7 +2099,7 @@ main (int argc, char **argv)
/* /*
Local Variables: Local Variables:
compile-command: "gcc -Wall -O -g -DTEST=1 -o minip12 minip12.c ../jnlib/libjnlib.a -L /usr/local/lib -lgcrypt -lgpg-error" compile-command: "gcc -Wall -O0 -g -DTEST=1 -o minip12 minip12.c ../jnlib/libjnlib.a -L /usr/local/lib -lgcrypt -lgpg-error"
End: End:
*/ */
#endif /* TEST */ #endif /* TEST */

View File

@ -6,7 +6,7 @@
@display @display
Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc. Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc.
59 Temple Place -- Suite 330, Boston, MA 02111-1307, USA 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Everyone is permitted to copy and distribute verbatim copies Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed. of this license document, but changing it is not allowed.
@ -352,7 +352,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License along You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc., with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@end smallexample @end smallexample
Also add information on how to contact you by electronic and paper mail. Also add information on how to contact you by electronic and paper mail.