Fixed importing certs created by newer versions of Mozilla.

This commit is contained in:
Werner Koch 2005-12-16 15:52:48 +00:00
parent f80ad71f1c
commit 38e7c4c50a
9 changed files with 285 additions and 56 deletions

5
NEWS
View File

@ -4,6 +4,11 @@ Noteworthy changes in version 1.9.20
* [scdaemon] Support for keypads of some readers. Tested only with * [scdaemon] Support for keypads of some readers. Tested only with
SPR532. New option --disable-keypad. SPR532. New option --disable-keypad.
* New debug tool gpgparsemail.
* Importing pkcs#12 files created be recent versions of Mozilla works
again.
Noteworthy changes in version 1.9.19 (2005-09-12) Noteworthy changes in version 1.9.19 (2005-09-12)
------------------------------------------------- -------------------------------------------------

4
TODO
View File

@ -94,3 +94,7 @@ might want to have an agent context for each service request
* sm/ * sm/
** --include-certs is as of now still a dummy command line option ** --include-certs is as of now still a dummy command line option
** check that we issue NO_SECKEY xxx if a -u key was not found
* gpg/
** issue a NO_SECKEY xxxx if a -u key was not found.

View File

@ -1,3 +1,13 @@
2005-12-16 Werner Koch <wk@g10code.com>
* minip12.c (cram_octet_string): New
(p12_parse): Use it for NDEFed bags.
(parse_bag_data): Ditto.
(string_to_key, set_key_iv, crypt_block): New arg SALTLEN.
(p12_build): Use old value 8 for new arg.
(parse_bag_encrypted_data, parse_bag_data): Allow for salts of 8
to 16 bytes. Add new arg R_CONSUMED.
2005-11-24 Werner Koch <wk@g10code.com> 2005-11-24 Werner Koch <wk@g10code.com>
* minip12.c (p12_parse): Fixed for case that the key object comes * minip12.c (p12_parse): Fixed for case that the key object comes

View File

@ -141,7 +141,8 @@ struct tag_info
/* Parse the buffer at the address BUFFER which is of SIZE and return /* Parse the buffer at the address BUFFER which is of SIZE and return
the tag and the length part from the TLV triplet. Update BUFFER the tag and the length part from the TLV triplet. Update BUFFER
and SIZE on success. */ and SIZE on success. Checks that the encoded length does not
exhaust the length of the provided buffer. */
static int static int
parse_tag (unsigned char const **buffer, size_t *size, struct tag_info *ti) parse_tag (unsigned char const **buffer, size_t *size, struct tag_info *ti)
{ {
@ -221,8 +222,76 @@ parse_tag (unsigned char const **buffer, size_t *size, struct tag_info *ti)
} }
/* Given an ASN.1 chunk of a structure like:
24 NDEF: OCTET STRING -- This is not passed to us
04 1: OCTET STRING -- INPUT point s to here
: 30
04 1: OCTET STRING
: 80
[...]
04 2: OCTET STRING
: 00 00
: } -- This denotes a Null tag and are the last
-- two bytes in INPUT.
Create a new buffer with the content of that octet string. INPUT
is the orginal buffer with a length as stored at LENGTH. Returns
NULL on error or a new malloced buffer with the length of this new
buffer stored at LENGTH and the number of bytes parsed from input
are added to the value stored at INPUT_CONSUMED. INPUT_CONSUMED is
allowed to be passed as NULL if the caller is not interested in
this value. */
static unsigned char *
cram_octet_string (const unsigned char *input, size_t *length,
size_t *input_consumed)
{
const unsigned char *s = input;
size_t n = *length;
unsigned char *output, *d;
struct tag_info ti;
/* Allocate output buf. We know that it won't be longer than the
input buffer. */
d = output = gcry_malloc (n);
if (!output)
goto bailout;
for (;;)
{
if (parse_tag (&s, &n, &ti))
goto bailout;
if (ti.class == UNIVERSAL && ti.tag == TAG_OCTET_STRING
&& !ti.ndef && !ti.is_constructed)
{
memcpy (d, s, ti.length);
s += ti.length;
d += ti.length;
n -= ti.length;
}
else if (ti.class == UNIVERSAL && !ti.tag && !ti.is_constructed)
break; /* Ready */
else
goto bailout;
}
*length = d - output;
if (input_consumed)
*input_consumed += s - input;
return output;
bailout:
if (input_consumed)
*input_consumed += s - input;
gcry_free (output);
return NULL;
}
static int static int
string_to_key (int id, char *salt, int iter, const char *pw, string_to_key (int id, char *salt, size_t saltlen, int iter, const char *pw,
int req_keylen, unsigned char *keybuf) int req_keylen, unsigned char *keybuf)
{ {
int rc, i, j; int rc, i, j;
@ -241,10 +310,16 @@ string_to_key (int id, char *salt, int iter, const char *pw,
return -1; return -1;
} }
if (saltlen < 8)
{
log_error ("salt too short\n");
return -1;
}
/* Store salt and password in BUF_I */ /* Store salt and password in BUF_I */
p = buf_i; p = buf_i;
for(i=0; i < 64; i++) for(i=0; i < 64; i++)
*p++ = salt [i%8]; *p++ = salt [i%saltlen];
for(i=j=0; i < 64; i += 2) for(i=j=0; i < 64; i += 2)
{ {
*p++ = 0; *p++ = 0;
@ -314,14 +389,14 @@ string_to_key (int id, char *salt, int iter, const char *pw,
static int static int
set_key_iv (gcry_cipher_hd_t chd, char *salt, int iter, const char *pw, set_key_iv (gcry_cipher_hd_t chd, char *salt, size_t saltlen, int iter,
int keybytes) const char *pw, int keybytes)
{ {
unsigned char keybuf[24]; unsigned char keybuf[24];
int rc; int rc;
assert (keybytes == 5 || keybytes == 24); assert (keybytes == 5 || keybytes == 24);
if (string_to_key (1, salt, iter, pw, keybytes, keybuf)) if (string_to_key (1, salt, saltlen, iter, pw, keybytes, keybuf))
return -1; return -1;
rc = gcry_cipher_setkey (chd, keybuf, keybytes); rc = gcry_cipher_setkey (chd, keybuf, keybytes);
if (rc) if (rc)
@ -330,7 +405,7 @@ set_key_iv (gcry_cipher_hd_t chd, char *salt, int iter, const char *pw,
return -1; return -1;
} }
if (string_to_key (2, salt, iter, pw, 8, keybuf)) if (string_to_key (2, salt, saltlen, iter, pw, 8, keybuf))
return -1; return -1;
rc = gcry_cipher_setiv (chd, keybuf, 8); rc = gcry_cipher_setiv (chd, keybuf, 8);
if (rc) if (rc)
@ -343,8 +418,8 @@ set_key_iv (gcry_cipher_hd_t chd, char *salt, int iter, const char *pw,
static void static void
crypt_block (unsigned char *buffer, size_t length, char *salt, int iter, crypt_block (unsigned char *buffer, size_t length, char *salt, size_t saltlen,
const char *pw, int cipher_algo, int encrypt) int iter, const char *pw, int cipher_algo, int encrypt)
{ {
gcry_cipher_hd_t chd; gcry_cipher_hd_t chd;
int rc; int rc;
@ -356,7 +431,7 @@ crypt_block (unsigned char *buffer, size_t length, char *salt, int iter,
wipememory (buffer, length); wipememory (buffer, length);
return; return;
} }
if (set_key_iv (chd, salt, iter, pw, if (set_key_iv (chd, salt, saltlen, iter, pw,
cipher_algo == GCRY_CIPHER_RFC2268_40? 5:24)) cipher_algo == GCRY_CIPHER_RFC2268_40? 5:24))
{ {
wipememory (buffer, length); wipememory (buffer, length);
@ -381,18 +456,22 @@ crypt_block (unsigned char *buffer, size_t length, char *salt, int iter,
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, 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)
{ {
struct tag_info ti; struct tag_info ti;
const unsigned char *p = buffer; const unsigned char *p = buffer;
const unsigned char *p_start = buffer;
size_t n = length; size_t n = length;
const char *where; const char *where;
char salt[8]; char salt[16];
size_t saltlen;
unsigned int iter; unsigned int iter;
unsigned char *plain = NULL; unsigned char *plain = NULL;
int bad_pass = 0; int bad_pass = 0;
unsigned char *cram_buffer = NULL;
size_t consumed = 0; /* Number of bytes consumed from the orginal buffer. */
where = "start"; where = "start";
if (parse_tag (&p, &n, &ti)) if (parse_tag (&p, &n, &ti))
@ -449,11 +528,13 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
goto bailout; goto bailout;
if (parse_tag (&p, &n, &ti)) if (parse_tag (&p, &n, &ti))
goto bailout; goto bailout;
if (ti.class || ti.tag != TAG_OCTET_STRING || ti.length != 8 ) if (ti.class || ti.tag != TAG_OCTET_STRING
|| ti.length < 8 || ti.length > 16 )
goto bailout; goto bailout;
memcpy (salt, p, 8); saltlen = ti.length;
p += 8; memcpy (salt, p, saltlen);
n -= 8; p += saltlen;
n -= saltlen;
if (parse_tag (&p, &n, &ti)) if (parse_tag (&p, &n, &ti))
goto bailout; goto bailout;
if (ti.class || ti.tag != TAG_INTEGER || !ti.length ) if (ti.class || ti.tag != TAG_INTEGER || !ti.length )
@ -468,7 +549,25 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
where = "rc2-ciphertext"; where = "rc2-ciphertext";
if (parse_tag (&p, &n, &ti)) if (parse_tag (&p, &n, &ti))
goto bailout; goto bailout;
if (ti.class != CONTEXT || ti.tag != 0 || !ti.length )
consumed = p - p_start;
if (ti.class == CONTEXT && ti.tag == 0 && ti.is_constructed && ti.ndef)
{
/* Mozilla exported certs now come with single byte chunks of
octect strings. (Mozilla Firefox 1.0.4). Arghh. */
where = "cram-rc2-ciphertext";
cram_buffer = cram_octet_string ( p, &n, &consumed);
if (!cram_buffer)
goto bailout;
p = p_start = cram_buffer;
if (r_consumed)
*r_consumed = consumed;
r_consumed = NULL; /* Ugly hack to not update that value any further. */
ti.length = n;
}
else if (ti.class == CONTEXT && ti.tag == 0 && ti.length )
;
else
goto bailout; goto bailout;
log_info ("%lu bytes of RC2 encrypted text\n", ti.length); log_info ("%lu bytes of RC2 encrypted text\n", ti.length);
@ -480,10 +579,11 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
goto bailout; goto bailout;
} }
memcpy (plain, p, ti.length); memcpy (plain, p, ti.length);
crypt_block (plain, ti.length, salt, iter, pw, GCRY_CIPHER_RFC2268_40, 0); crypt_block (plain, ti.length, salt, saltlen,
iter, pw, GCRY_CIPHER_RFC2268_40, 0);
n = ti.length; n = ti.length;
startoffset = 0; startoffset = 0;
buffer = p = plain; p_start = p = plain;
/* { */ /* { */
/* # warning debug code is enabled */ /* # warning debug code is enabled */
@ -615,13 +715,19 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
} }
} }
if (r_consumed)
*r_consumed = consumed;
gcry_free (plain); gcry_free (plain);
gcry_free (cram_buffer);
return 0; return 0;
bailout: bailout:
if (r_consumed)
*r_consumed = consumed;
gcry_free (plain); gcry_free (plain);
gcry_free (cram_buffer);
log_error ("encryptedData error at \"%s\", offset %u\n", log_error ("encryptedData error at \"%s\", offset %u\n",
where, (p - buffer)+startoffset); where, (p - p_start)+startoffset);
if (bad_pass) if (bad_pass)
{ {
/* Note, that the following string might be used by other programs /* Note, that the following string might be used by other programs
@ -634,19 +740,23 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
static gcry_mpi_t * static gcry_mpi_t *
parse_bag_data (const unsigned char *buffer, size_t length, int startoffset, parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
const char *pw) size_t *r_consumed, const char *pw)
{ {
int rc; int rc;
struct tag_info ti; struct tag_info ti;
const unsigned char *p = buffer; const unsigned char *p = buffer;
const unsigned char *p_start = buffer;
size_t n = length; size_t n = length;
const char *where; const char *where;
char salt[8]; char salt[16];
size_t saltlen;
unsigned int iter; unsigned int iter;
int len; int len;
unsigned char *plain = NULL; unsigned char *plain = NULL;
gcry_mpi_t *result = NULL; gcry_mpi_t *result = NULL;
int result_count, i; int result_count, i;
unsigned char *cram_buffer = NULL;
size_t consumed = 0; /* Number of bytes consumed from the orginal buffer. */
where = "start"; where = "start";
if (parse_tag (&p, &n, &ti)) if (parse_tag (&p, &n, &ti))
@ -658,6 +768,22 @@ parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
if (ti.class || ti.tag != TAG_OCTET_STRING) if (ti.class || ti.tag != TAG_OCTET_STRING)
goto bailout; goto bailout;
consumed = p - p_start;
if (ti.is_constructed && ti.ndef)
{
/* Mozilla exported certs now come with single byte chunks of
octect strings. (Mozilla Firefox 1.0.4). Arghh. */
where = "cram-data.outersegs";
cram_buffer = cram_octet_string ( p, &n, &consumed);
if (!cram_buffer)
goto bailout;
p = p_start = cram_buffer;
if (r_consumed)
*r_consumed = consumed;
r_consumed = NULL; /* Ugly hack to not update that value any further. */
}
where = "data.outerseqs"; where = "data.outerseqs";
if (parse_tag (&p, &n, &ti)) if (parse_tag (&p, &n, &ti))
goto bailout; goto bailout;
@ -709,11 +835,13 @@ parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
goto bailout; goto bailout;
if (parse_tag (&p, &n, &ti)) if (parse_tag (&p, &n, &ti))
goto bailout; goto bailout;
if (ti.class || ti.tag != TAG_OCTET_STRING || ti.length != 8 ) if (ti.class || ti.tag != TAG_OCTET_STRING
|| ti.length < 8 || ti.length > 16)
goto bailout; goto bailout;
memcpy (salt, p, 8); saltlen = ti.length;
p += 8; memcpy (salt, p, saltlen);
n -= 8; p += saltlen;
n -= saltlen;
if (parse_tag (&p, &n, &ti)) if (parse_tag (&p, &n, &ti))
goto bailout; goto bailout;
if (ti.class || ti.tag != TAG_INTEGER || !ti.length ) if (ti.class || ti.tag != TAG_INTEGER || !ti.length )
@ -740,10 +868,11 @@ parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
goto bailout; goto bailout;
} }
memcpy (plain, p, ti.length); memcpy (plain, p, ti.length);
crypt_block (plain, ti.length, salt, iter, pw, GCRY_CIPHER_3DES, 0); consumed += p - p_start + ti.length;
crypt_block (plain, ti.length, salt, saltlen, iter, pw, GCRY_CIPHER_3DES, 0);
n = ti.length; n = ti.length;
startoffset = 0; startoffset = 0;
buffer = p = plain; p_start = p = plain;
/* { */ /* { */
/* # warning debug code is enabled */ /* # warning debug code is enabled */
@ -828,6 +957,9 @@ parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
if (len) if (len)
goto bailout; goto bailout;
gcry_free (cram_buffer);
if (r_consumed)
*r_consumed = consumed;
return result; return result;
bailout: bailout:
@ -838,8 +970,11 @@ parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
gcry_mpi_release (result[i]); gcry_mpi_release (result[i]);
gcry_free (result); gcry_free (result);
} }
gcry_free (cram_buffer);
log_error ( "data error at \"%s\", offset %u\n", log_error ( "data error at \"%s\", offset %u\n",
where, (p - buffer) + startoffset); where, (p - buffer) + startoffset);
if (r_consumed)
*r_consumed = consumed;
return NULL; return NULL;
} }
@ -857,10 +992,13 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
{ {
struct tag_info ti; struct tag_info ti;
const unsigned char *p = buffer; const unsigned char *p = buffer;
const unsigned char *p_start = buffer;
size_t n = length; size_t n = length;
const char *where; const char *where;
int bagseqlength, len; int bagseqlength, len;
int bagseqndef, lenndef;
gcry_mpi_t *result = NULL; gcry_mpi_t *result = NULL;
unsigned char *cram_buffer = NULL;
where = "pfx"; where = "pfx";
if (parse_tag (&p, &n, &ti)) if (parse_tag (&p, &n, &ti))
@ -897,71 +1035,121 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
if (ti.class != UNIVERSAL || ti.tag != TAG_OCTET_STRING) if (ti.class != UNIVERSAL || ti.tag != TAG_OCTET_STRING)
goto bailout; goto bailout;
if (ti.is_constructed && ti.ndef)
{
/* Mozilla exported certs now come with single byte chunks of
octect strings. (Mozilla Firefox 1.0.4). Arghh. */
where = "cram-bags";
cram_buffer = cram_octet_string ( p, &n, NULL);
if (!cram_buffer)
goto bailout;
p = p_start = cram_buffer;
}
where = "bags"; where = "bags";
if (parse_tag (&p, &n, &ti)) if (parse_tag (&p, &n, &ti))
goto bailout; goto bailout;
if (ti.class != UNIVERSAL || ti.tag != TAG_SEQUENCE) if (ti.class != UNIVERSAL || ti.tag != TAG_SEQUENCE)
goto bailout; goto bailout;
bagseqndef = ti.ndef;
bagseqlength = ti.length; bagseqlength = ti.length;
while (bagseqlength) while (bagseqlength || bagseqndef)
{ {
/*log_debug ( "at offset %u\n", (p - buffer));*/ 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;
if (bagseqndef && ti.class == UNIVERSAL && !ti.tag && !ti.is_constructed)
break; /* Ready */
if (ti.class != UNIVERSAL || ti.tag != TAG_SEQUENCE) if (ti.class != UNIVERSAL || ti.tag != TAG_SEQUENCE)
goto bailout; goto bailout;
if (bagseqlength < ti.nhdr) if (!bagseqndef)
goto bailout; {
bagseqlength -= ti.nhdr; if (bagseqlength < ti.nhdr)
if (bagseqlength < ti.length) goto bailout;
goto bailout; bagseqlength -= ti.nhdr;
bagseqlength -= ti.length; if (bagseqlength < ti.length)
goto bailout;
bagseqlength -= ti.length;
}
lenndef = ti.ndef;
len = ti.length; len = ti.length;
if (parse_tag (&p, &n, &ti)) if (parse_tag (&p, &n, &ti))
goto bailout; goto bailout;
len -= ti.nhdr; if (lenndef)
len = ti.nhdr;
else
len -= ti.nhdr;
if (ti.tag == TAG_OBJECT_ID && ti.length == DIM(oid_encryptedData) if (ti.tag == TAG_OBJECT_ID && ti.length == DIM(oid_encryptedData)
&& !memcmp (p, oid_encryptedData, DIM(oid_encryptedData))) && !memcmp (p, oid_encryptedData, DIM(oid_encryptedData)))
{ {
size_t consumed = 0;
p += DIM(oid_encryptedData); p += DIM(oid_encryptedData);
n -= DIM(oid_encryptedData); n -= DIM(oid_encryptedData);
len -= DIM(oid_encryptedData); if (!lenndef)
len -= DIM(oid_encryptedData);
where = "bag.encryptedData"; where = "bag.encryptedData";
if (parse_bag_encrypted_data (p, n, (p - buffer), pw, if (parse_bag_encrypted_data (p, n, (p - p_start), &consumed, pw,
certcb, certcbarg)) certcb, certcbarg))
goto bailout; goto bailout;
if (lenndef)
len += consumed;
} }
else if (ti.tag == TAG_OBJECT_ID && ti.length == DIM(oid_data) else if (ti.tag == TAG_OBJECT_ID && ti.length == DIM(oid_data)
&& !memcmp (p, oid_data, DIM(oid_data))) && !memcmp (p, oid_data, DIM(oid_data)))
{ {
if (result) if (result)
log_info ("already got an data object, skipping next one\n"); {
log_info ("already got an data object, skipping next one\n");
p += ti.length;
n -= ti.length;
}
else else
{ {
size_t consumed = 0;
p += DIM(oid_data); p += DIM(oid_data);
n -= DIM(oid_data); n -= DIM(oid_data);
len -= DIM(oid_data); if (!lenndef)
result = parse_bag_data (p, n, (p-buffer), pw); len -= DIM(oid_data);
result = parse_bag_data (p, n, (p - p_start), &consumed, pw);
if (!result) if (!result)
goto bailout; goto bailout;
if (lenndef)
len += consumed;
} }
} }
else else
log_info ( "unknown bag type - skipped\n"); {
log_info ("unknown bag type - skipped\n");
p += ti.length;
n -= ti.length;
}
if (len < 0 || len > n) if (len < 0 || len > n)
goto bailout; goto bailout;
p += len; p += len;
n -= len; n -= len;
if (lenndef)
{
/* Need to skip the Null Tag. */
if (parse_tag (&p, &n, &ti))
goto bailout;
if (!(ti.class == UNIVERSAL && !ti.tag && !ti.is_constructed))
goto bailout;
}
} }
gcry_free (cram_buffer);
return result; return result;
bailout: bailout:
log_error ("error at \"%s\", offset %u\n", where, (p - buffer)); log_error ("error at \"%s\", offset %u\n", where, (p - p_start));
/* fixme: need to release RESULT. */ /* fixme: need to release RESULT. */
gcry_free (cram_buffer);
return NULL; return NULL;
} }
@ -1586,7 +1774,8 @@ p12_build (gcry_mpi_t *kparms, unsigned char *cert, size_t certlen,
/* Encrypt it. */ /* Encrypt it. */
gcry_randomize (salt, 8, GCRY_STRONG_RANDOM); gcry_randomize (salt, 8, GCRY_STRONG_RANDOM);
crypt_block (buffer, buflen, salt, 2048, pw, GCRY_CIPHER_RFC2268_40, 1); crypt_block (buffer, buflen, salt, 8, 2048, pw,
GCRY_CIPHER_RFC2268_40, 1);
/* Encode the encrypted stuff into a bag. */ /* Encode the encrypted stuff into a bag. */
seqlist[seqlistidx].buffer = build_cert_bag (buffer, buflen, salt, &n); seqlist[seqlistidx].buffer = build_cert_bag (buffer, buflen, salt, &n);
@ -1607,7 +1796,7 @@ p12_build (gcry_mpi_t *kparms, unsigned char *cert, size_t certlen,
/* Encrypt it. */ /* Encrypt it. */
gcry_randomize (salt, 8, GCRY_STRONG_RANDOM); gcry_randomize (salt, 8, GCRY_STRONG_RANDOM);
crypt_block (buffer, buflen, salt, 2048, pw, GCRY_CIPHER_3DES, 1); crypt_block (buffer, buflen, salt, 8, 2048, pw, GCRY_CIPHER_3DES, 1);
/* Encode the encrypted stuff into a bag. */ /* Encode the encrypted stuff into a bag. */
seqlist[seqlistidx].buffer = build_key_bag (buffer, buflen, salt, &n); seqlist[seqlistidx].buffer = build_key_bag (buffer, buflen, salt, &n);

View File

@ -14,6 +14,7 @@ GnuPG comes with a couple of smaller tools:
* gpgsm-gencert.sh:: Generate an X.509 certificate request. * gpgsm-gencert.sh:: Generate an X.509 certificate request.
* gpg-preset-passphrase:: Put a passphrase into the cache. * gpg-preset-passphrase:: Put a passphrase into the cache.
* gpg-connect-agent:: Communicate with a running agent. * gpg-connect-agent:: Communicate with a running agent.
* gpgparsemail:: Parse a mail message into an annotated format
* symcryptrun:: Call a simple symmetric encryption tool. * symcryptrun:: Call a simple symmetric encryption tool.
@end menu @end menu
@ -773,6 +774,17 @@ be used to directly connect to any Assuan style socket server.
@end table @end table
@c
@c GPGPARSEMAIL
@c
@node gpgparsemail
@section Parse a mail message into an annotated format
The @command{gpgparsemail} is a utility currentlu only useful for
debugging. Run it with @code{--help} for usage information.
@c @c
@c SYMCRYPTRUN @c SYMCRYPTRUN
@c @c

View File

@ -1,5 +1,7 @@
2005-12-14 Werner Koch <wk@g10code.com> 2005-12-14 Werner Koch <wk@g10code.com>
* Makefile.am (bin_PROGRAMS): Build gpgparsemail.
* gpgparsemail.c (pkcs7_begin): New. * gpgparsemail.c (pkcs7_begin): New.
(parse_message, message_cb): Add support of direct pkcs signatures. (parse_message, message_cb): Add support of direct pkcs signatures.

View File

@ -18,7 +18,6 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
EXTRA_DIST = Manifest watchgnupg.c \ EXTRA_DIST = Manifest watchgnupg.c \
rfc822parse.c rfc822parse.h gpgparsemail.c \
addgnupghome gpgsm-gencert.sh addgnupghome gpgsm-gencert.sh
AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/common AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/common
@ -36,7 +35,7 @@ else
symcryptrun = symcryptrun =
endif endif
bin_PROGRAMS = gpgconf gpg-connect-agent gpgkey2ssh ${symcryptrun} bin_PROGRAMS = gpgconf gpg-connect-agent gpgkey2ssh ${symcryptrun} gpgparsemail
if !HAVE_W32_SYSTEM if !HAVE_W32_SYSTEM
bin_PROGRAMS += watchgnupg bin_PROGRAMS += watchgnupg
endif endif
@ -46,6 +45,9 @@ gpgconf_SOURCES = gpgconf.c gpgconf.h gpgconf-comp.c no-libgcrypt.c
gpgconf_LDADD = ../jnlib/libjnlib.a \ gpgconf_LDADD = ../jnlib/libjnlib.a \
../common/libcommon.a ../gl/libgnu.a @LIBINTL@ ../common/libcommon.a ../gl/libgnu.a @LIBINTL@
gpgparsemail_SOURCES = gpgparsemail.c rfc822parse.c rfc822parse.h
gpgparsemail_LDADD =
symcryptrun_SOURCES = symcryptrun.c symcryptrun_SOURCES = symcryptrun.c
symcryptrun_LDADD = $(LIBUTIL_LIBS) ../jnlib/libjnlib.a \ symcryptrun_LDADD = $(LIBUTIL_LIBS) ../jnlib/libjnlib.a \
../common/libcommon.a ../gl/libgnu.a \ ../common/libcommon.a ../gl/libgnu.a \

View File

@ -21,8 +21,8 @@
/* This utility prints an RFC8222, possible MIME structured, message /* This utility prints an RFC8222, possible MIME structured, message
in an annotated format with the first column having an indicator in an annotated format with the first column having an indicator
for the content of the line.. Several options are available to for the content of the line. Several options are available to
scrutinize the message. S/MIME and OpenPGP suuport is included. */ scrutinize the message. S/MIME and OpenPGP support is included. */
#include <stdio.h> #include <stdio.h>
@ -708,6 +708,8 @@ main (int argc, char **argv)
" --debug enable additional debug output\n" " --debug enable additional debug output\n"
" --help display this help and exit\n\n" " --help display this help and exit\n\n"
"With no FILE, or when FILE is -, read standard input.\n\n" "With no FILE, or when FILE is -, read standard input.\n\n"
"WARNING: This tool is under development.\n"
" The semantics may change without notice\n\n"
"Report bugs to <bug-gnupg@gnu.org>."); "Report bugs to <bug-gnupg@gnu.org>.");
exit (0); exit (0);
} }

View File

@ -155,7 +155,7 @@ capitalize_header_name (unsigned char *name)
*name = *name - 'A' + 'a'; *name = *name - 'A' + 'a';
} }
#ifndef HAVE_STPCPY
static char * static char *
stpcpy (char *a,const char *b) stpcpy (char *a,const char *b)
{ {
@ -165,6 +165,7 @@ stpcpy (char *a,const char *b)
return (char*)a; return (char*)a;
} }
#endif
/* If a callback has been registerd, call it for the event of type /* If a callback has been registerd, call it for the event of type
@ -474,7 +475,7 @@ insert_body (rfc822parse_t msg, const unsigned char *line, size_t length)
msg->boundary = NULL; /* No current boundary anymore. */ msg->boundary = NULL; /* No current boundary anymore. */
set_current_part_to_parent (msg); set_current_part_to_parent (msg);
/* Fixme: The next should acctually be sent right before the /* Fixme: The next should actually be send right before the
next boundary, so that we can mark the epilogue. */ next boundary, so that we can mark the epilogue. */
if (!rc) if (!rc)
rc = do_callback (msg, RFC822PARSE_LEVEL_UP); rc = do_callback (msg, RFC822PARSE_LEVEL_UP);
@ -523,7 +524,8 @@ rfc822parse_finish (rfc822parse_t msg)
* available. * available.
* *
* If VALUEOFF is not NULL it will receive the offset of the first non * If VALUEOFF is not NULL it will receive the offset of the first non
* space character in th value of the line. * space character in the value part of the line (i.e. after the first
* colon).
*/ */
char * char *
rfc822parse_get_field (rfc822parse_t msg, const char *name, int which, rfc822parse_get_field (rfc822parse_t msg, const char *name, int which,
@ -758,7 +760,8 @@ parse_field (HDR_LINE hdr)
static const char specials[] = "<>@.,;:\\[]\"()"; static const char specials[] = "<>@.,;:\\[]\"()";
static const char specials2[] = "<>@.,;:"; static const char specials2[] = "<>@.,;:";
static const char tspecials[] = "/?=<>@,;:\\[]\"()"; static const char tspecials[] = "/?=<>@,;:\\[]\"()";
static const char tspecials2[] = "/?=<>@.,;:"; static const char tspecials2[] = "/?=<>@.,;:"; /* FIXME: really
include '.'?*/
static struct static struct
{ {
const unsigned char *name; const unsigned char *name;