diff --git a/NEWS b/NEWS index e6cfb2b4a..2e7201d1e 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,9 @@ Noteworthy changes in version 1.9.22 * Enhanced pkcs#12 support to allow import from simple keyBags. + * Exporting to pkcs#12 now create bag attributes so that Mozilla is + able to import the files. + Noteworthy changes in version 1.9.21 (2006-06-20) ------------------------------------------------- diff --git a/agent/ChangeLog b/agent/ChangeLog index e3d69d8b4..2048f5c18 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,11 @@ +2006-07-24 Werner Koch + + * minip12.c (build_key_bag): New args SHA1HASH and + KEYIDSTR. Append bag Attributes if these args are given. + (build_cert_sequence): ditto. + (p12_build): Calculate certificate hash and pass to build + functions. + 2006-07-21 Werner Koch * minip12.c (oid_pkcs_12_keyBag): New. diff --git a/agent/minip12.c b/agent/minip12.c index 243116d25..536170856 100644 --- a/agent/minip12.c +++ b/agent/minip12.c @@ -134,6 +134,23 @@ static unsigned char const data_mactemplate[51] = { #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; @@ -1648,6 +1665,7 @@ build_key_sequence (gcry_mpi_t *kparms, size_t *r_length) 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; @@ -1671,6 +1689,10 @@ build_key_bag (unsigned char *buffer, size_t buflen, char *salt, 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); @@ -1741,12 +1763,26 @@ build_key_bag (unsigned char *buffer, size_t buflen, char *salt, memcpy (p + DATA_3DESITER2048_SALT_OFF, salt, 8); p += DIM (data_3desiter2048); - /* 10. And finally the octet string with the encrypted data. */ + /* 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); @@ -1856,13 +1892,17 @@ build_cert_bag (unsigned char *buffer, size_t buflen, char *salt, static unsigned char * -build_cert_sequence (unsigned char *buffer, size_t buflen, size_t *r_length) +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. */ @@ -1884,6 +1924,10 @@ build_cert_sequence (unsigned char *buffer, size_t buflen, size_t *r_length) 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); @@ -1932,16 +1976,27 @@ build_cert_sequence (unsigned char *buffer, size_t buflen, size_t *r_length) /* 6. Store a [0] tag. */ p = store_tag_length (p, 0xa0, len[6]); - /* 7. And finally the octet string with the actual certificate. */ + /* 7. And the octet string with the actual certificate. */ p = store_tag_length (p, TAG_OCTET_STRING, buflen); memcpy (p, buffer, buflen); p += buflen; - certseqlen = p - certseq; + /* 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++) @@ -1964,13 +2019,23 @@ p12_build (gcry_mpi_t *kparms, unsigned char *cert, size_t certlen, char salt[8]; struct buffer_s seqlist[3]; int seqlistidx = 0; + unsigned char sha1hash[20]; + char keyidstr[8+1]; n = buflen = 0; /* (avoid compiler warning). */ + memset (sha1hash, 0, 20); + *keyidstr = 0; 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, &buflen); + buffer = build_cert_sequence (cert, certlen, sha1hash, keyidstr, + &buflen); if (!buffer) goto failure; @@ -1989,6 +2054,7 @@ p12_build (gcry_mpi_t *kparms, unsigned char *cert, size_t certlen, seqlistidx++; } + if (kparms) { /* Encode the key. */ @@ -2001,7 +2067,12 @@ p12_build (gcry_mpi_t *kparms, unsigned char *cert, size_t certlen, crypt_block (buffer, buflen, salt, 8, 2048, pw, GCRY_CIPHER_3DES, 1); /* Encode the encrypted stuff into a bag. */ - seqlist[seqlistidx].buffer = build_key_bag (buffer, buflen, salt, &n); + 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; diff --git a/tests/pkits/README b/tests/pkits/README index 1f944ad58..79678cf30 100644 --- a/tests/pkits/README +++ b/tests/pkits/README @@ -7,3 +7,6 @@ http://csrc.nist.gov/pki/testing/x509paths.html . README - this file. PKITS_data.tar.bz2 - the orginal ZIP file, repackaged as a tarball. Makefile.am - Part of our build system. + + +The password for the p12 files is "password".