mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Support import from TrustedMIME (i.e. from simple keyBags)
This commit is contained in:
parent
4954c5f1c3
commit
d035d2a52e
2
NEWS
2
NEWS
@ -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)
|
||||
-------------------------------------------------
|
||||
|
@ -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>
|
||||
|
||||
* gpg-agent.c (handle_signal): Print infor for SIGUSR2 only in
|
||||
|
237
agent/minip12.c
237
agent/minip12.c
@ -88,6 +88,8 @@ static unsigned char const oid_data[9] = {
|
||||
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 };
|
||||
static unsigned char const oid_encryptedData[9] = {
|
||||
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] = {
|
||||
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x0A, 0x01, 0x02 };
|
||||
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
|
||||
parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
|
||||
int startoffset, size_t *r_consumed, const char *pw,
|
||||
void (*certcb)(void*, const unsigned char*, size_t),
|
||||
void *certcbarg)
|
||||
void *certcbarg, gcry_mpi_t **r_result)
|
||||
{
|
||||
struct tag_info ti;
|
||||
const unsigned char *p = buffer;
|
||||
@ -483,7 +487,12 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
|
||||
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;
|
||||
gcry_mpi_t *result = NULL;
|
||||
int result_count;
|
||||
|
||||
if (r_result)
|
||||
*r_result = NULL;
|
||||
where = "start";
|
||||
if (parse_tag (&p, &n, &ti))
|
||||
goto bailout;
|
||||
@ -529,10 +538,19 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
|
||||
p += 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
|
||||
goto bailout;
|
||||
|
||||
where = "rc2-params";
|
||||
where = "rc2or3des-params";
|
||||
if (parse_tag (&p, &n, &ti))
|
||||
goto bailout;
|
||||
if (ti.class || ti.tag != TAG_SEQUENCE)
|
||||
@ -557,7 +575,7 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
|
||||
n--;
|
||||
}
|
||||
|
||||
where = "rc2-ciphertext";
|
||||
where = "rc2or3des-ciphertext";
|
||||
if (parse_tag (&p, &n, &ti))
|
||||
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
|
||||
octect strings. (Mozilla Firefox 1.0.4). Arghh. */
|
||||
where = "cram-rc2-ciphertext";
|
||||
where = "cram-rc2or3des-ciphertext";
|
||||
cram_buffer = cram_octet_string ( p, &n, &consumed);
|
||||
if (!cram_buffer)
|
||||
goto bailout;
|
||||
@ -581,7 +599,7 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
|
||||
else
|
||||
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);
|
||||
if (!plain)
|
||||
@ -591,7 +609,9 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
|
||||
}
|
||||
memcpy (plain, p, ti.length);
|
||||
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;
|
||||
startoffset = 0;
|
||||
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. */
|
||||
while (n)
|
||||
{
|
||||
int isbag = 0;
|
||||
int iscrlbag = 0;
|
||||
int iskeybag = 0;
|
||||
|
||||
where = "certbag.nextcert";
|
||||
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);
|
||||
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
|
||||
goto bailout;
|
||||
@ -657,14 +688,106 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
|
||||
goto bailout;
|
||||
if (ti.class != CONTEXT || ti.tag)
|
||||
goto bailout;
|
||||
if (isbag)
|
||||
if (iscrlbag)
|
||||
{
|
||||
log_info ("skipping unsupported crlBag\n");
|
||||
p += 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
|
||||
{
|
||||
log_info ("processing certBag\n");
|
||||
if (parse_tag (&p, &n, &ti))
|
||||
goto bailout;
|
||||
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;
|
||||
gcry_free (plain);
|
||||
gcry_free (cram_buffer);
|
||||
if (r_result)
|
||||
*r_result = result;
|
||||
return 0;
|
||||
|
||||
bailout:
|
||||
if (result)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; result[i]; i++)
|
||||
gcry_mpi_release (result[i]);
|
||||
gcry_free (result);
|
||||
}
|
||||
if (r_consumed)
|
||||
*r_consumed = consumed;
|
||||
gcry_free (plain);
|
||||
@ -1066,7 +1199,7 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
|
||||
bagseqlength = ti.length;
|
||||
while (bagseqlength || bagseqndef)
|
||||
{
|
||||
log_debug ( "at offset %u\n", (p - p_start));
|
||||
/* log_debug ( "at offset %u\n", (p - p_start)); */
|
||||
where = "bag-sequence";
|
||||
if (parse_tag (&p, &n, &ti))
|
||||
goto bailout;
|
||||
@ -1105,7 +1238,8 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
|
||||
len -= DIM(oid_encryptedData);
|
||||
where = "bag.encryptedData";
|
||||
if (parse_bag_encrypted_data (p, n, (p - p_start), &consumed, pw,
|
||||
certcb, certcbarg))
|
||||
certcb, certcbarg,
|
||||
result? NULL : &result))
|
||||
goto bailout;
|
||||
if (lenndef)
|
||||
len += consumed;
|
||||
@ -1115,7 +1249,7 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
|
||||
{
|
||||
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;
|
||||
n -= ti.length;
|
||||
}
|
||||
@ -1159,7 +1293,14 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
|
||||
return result;
|
||||
bailout:
|
||||
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);
|
||||
return NULL;
|
||||
}
|
||||
@ -1227,6 +1368,8 @@ create_final (struct buffer_s *sequences, const char *pw, size_t *r_length)
|
||||
unsigned char keybuf[20];
|
||||
gcry_md_hd_t md;
|
||||
int rc;
|
||||
int with_mac = 1;
|
||||
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 0. And the final outer sequence. */
|
||||
needed += DIM (data_mactemplate);
|
||||
if (with_mac)
|
||||
needed += DIM (data_mactemplate);
|
||||
len[0] = needed;
|
||||
n = compute_tag_length (needed);
|
||||
needed += n;
|
||||
@ -1311,37 +1455,40 @@ create_final (struct buffer_s *sequences, const char *pw, size_t *r_length)
|
||||
p += sequences[i].length;
|
||||
}
|
||||
|
||||
/* Intermezzo to compute the MAC. */
|
||||
maclen = p - macstart;
|
||||
gcry_randomize (salt, 8, GCRY_STRONG_RANDOM);
|
||||
if (string_to_key (3, salt, 8, 2048, pw, 20, keybuf))
|
||||
if (with_mac)
|
||||
{
|
||||
gcry_free (result);
|
||||
return NULL;
|
||||
}
|
||||
rc = gcry_md_open (&md, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("gcry_md_open failed: %s\n", gpg_strerror (rc));
|
||||
gcry_free (result);
|
||||
return NULL;
|
||||
}
|
||||
rc = gcry_md_setkey (md, keybuf, 20);
|
||||
if (rc)
|
||||
{
|
||||
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);
|
||||
/* Intermezzo to compute the 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);
|
||||
return NULL;
|
||||
}
|
||||
rc = gcry_md_open (&md, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("gcry_md_open failed: %s\n", gpg_strerror (rc));
|
||||
gcry_free (result);
|
||||
return NULL;
|
||||
}
|
||||
rc = gcry_md_setkey (md, keybuf, 20);
|
||||
if (rc)
|
||||
{
|
||||
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. */
|
||||
memcpy (p, data_mactemplate, DIM (data_mactemplate));
|
||||
memcpy (p + DATA_MACTEMPLATE_SALT_OFF, salt, 8);
|
||||
memcpy (p + DATA_MACTEMPLATE_MAC_OFF, gcry_md_read (md, 0), 20);
|
||||
p += DIM (data_mactemplate);
|
||||
gcry_md_close (md);
|
||||
/* 8. Append the MAC template and fix it up. */
|
||||
memcpy (p, data_mactemplate, DIM (data_mactemplate));
|
||||
memcpy (p + DATA_MACTEMPLATE_SALT_OFF, salt, 8);
|
||||
memcpy (p + DATA_MACTEMPLATE_MAC_OFF, gcry_md_read (md, 0), 20);
|
||||
p += DIM (data_mactemplate);
|
||||
gcry_md_close (md);
|
||||
}
|
||||
|
||||
/* Ready. */
|
||||
resultlen = p - result;
|
||||
@ -1952,7 +2099,7 @@ main (int argc, char **argv)
|
||||
|
||||
/*
|
||||
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:
|
||||
*/
|
||||
#endif /* TEST */
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
@display
|
||||
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
|
||||
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
|
||||
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
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
Loading…
x
Reference in New Issue
Block a user