diff --git a/agent/ChangeLog b/agent/ChangeLog index 999fbae3c..7c4799d1c 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,8 @@ +2006-06-20 Werner Koch + + * minip12.c (create_final): New arg PW. Add code to calculate the + MAC. + 2006-06-09 Marcus Brinkmann * Makefile.am (gpg_agent_LDADD): Add $(NETLIBS). diff --git a/agent/minip12.c b/agent/minip12.c index e65bf0617..6f99bf24d 100644 --- a/agent/minip12.c +++ b/agent/minip12.c @@ -1,5 +1,5 @@ /* minip12.c - A minimal pkcs-12 implementation. - * Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + * Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -120,6 +120,16 @@ static unsigned char const data_rc2iter2048[30] = { 0xFF, 0xFF, 0x02, 0x02, 0x08, 0x00 }; #define DATA_RC2ITER2048_SALT_OFF 18 +static unsigned char const data_mactemplate[51] = { + 0x30, 0x31, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, + 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, + 0x14, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x04, 0x08, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, + 0x02, 0x08, 0x00 }; +#define DATA_MACTEMPLATE_MAC_OFF 17 +#define DATA_MACTEMPLATE_SALT_OFF 39 struct buffer_s { @@ -1200,17 +1210,27 @@ store_tag_length (unsigned char *p, int tag, size_t n) /* Create the final PKCS-12 object from the sequences contained in - SEQLIST. That array is terminated with an NULL object */ + SEQLIST. PW is the password. That array is terminated with an NULL + object. */ static unsigned char * -create_final (struct buffer_s *sequences, size_t *r_length) +create_final (struct buffer_s *sequences, const char *pw, size_t *r_length) { int i; size_t needed = 0; size_t len[8], n; + unsigned char *macstart; + size_t maclen; unsigned char *result, *p; size_t resultlen; + char salt[8]; + unsigned char keybuf[20]; + gcry_md_hd_t md; + int rc; - /* 8 steps to create the pkcs#12 Krampf. */ + /* 9 steps to create the pkcs#12 Krampf. */ + + /* 8. The MAC. */ + /* We add this at step 0. */ /* 7. All the buffers. */ for (i=0; sequences[i].buffer; i++) @@ -1243,6 +1263,7 @@ create_final (struct buffer_s *sequences, size_t *r_length) needed += 3; /* 0. And the final outer sequence. */ + needed += DIM (data_mactemplate); len[0] = needed; n = compute_tag_length (needed); needed += n; @@ -1263,7 +1284,7 @@ create_final (struct buffer_s *sequences, size_t *r_length) *p++ = TAG_INTEGER; *p++ = 1; *p++ = 3; - + /* 2. Store another sequence. */ p = store_tag_length (p, TAG_SEQUENCE, len[2]); @@ -1279,6 +1300,7 @@ create_final (struct buffer_s *sequences, size_t *r_length) p = store_tag_length (p, TAG_OCTET_STRING, len[5]); /* 6. And the inner sequence. */ + macstart = p; p = store_tag_length (p, TAG_SEQUENCE, len[6]); /* 7. Append all the buffers. */ @@ -1288,6 +1310,38 @@ create_final (struct buffer_s *sequences, 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)) + { + 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); + /* Ready. */ resultlen = p - result; if (needed != resultlen) @@ -1811,7 +1865,7 @@ p12_build (gcry_mpi_t *kparms, unsigned char *cert, size_t certlen, seqlist[seqlistidx].buffer = NULL; seqlist[seqlistidx].length = 0; - buffer = create_final (seqlist, &buflen); + buffer = create_final (seqlist, pw, &buflen); failure: for ( ; seqlistidx; seqlistidx--)