summaryrefslogtreecommitdiffstats
path: root/sm
diff options
context:
space:
mode:
Diffstat (limited to 'sm')
-rw-r--r--sm/minip12.c860
1 files changed, 67 insertions, 793 deletions
diff --git a/sm/minip12.c b/sm/minip12.c
index 98eb4e3b5..ae81d821b 100644
--- a/sm/minip12.c
+++ b/sm/minip12.c
@@ -150,57 +150,6 @@ struct buffer_s
};
-struct tag_info
-{
- int class;
- int is_constructed;
- unsigned long tag;
- size_t length; /* length part of the TLV */
- size_t nhdr;
- int ndef; /* It is an indefinite length */
-};
-
-
-#define TLV_MAX_DEPTH 20
-
-
-struct bufferlist_s
-{
- struct bufferlist_s *next;
- char *buffer;
-};
-
-
-/* An object to control the ASN.1 parsing. */
-struct tlv_ctx_s
-{
- /* The orginal buffer with the entire pkcs#12 object and its length. */
- const unsigned char *origbuffer;
- size_t origbufsize;
-
- /* The current buffer we are working on and its length. */
- const unsigned char *buffer;
- size_t bufsize;
-
- int in_ndef; /* Flag indicating that we are in a NDEF. */
- int pending; /* The last tlv_next has not yet been processed. */
-
- struct tag_info ti; /* The current tag. */
- gpg_error_t lasterr; /* Last error from tlv function. */
- const char *lastfunc;/* Name of last called function. */
-
- struct bufferlist_s *bufferlist; /* To keep track of malloced buffers. */
-
- unsigned int stacklen; /* Used size of the stack. */
- struct {
- const unsigned char *buffer; /* Saved value of BUFFER. */
- size_t bufsize; /* Saved value of BUFSIZE. */
- size_t length; /* Length of the container (ti.length). */
- int in_ndef; /* Saved IN_NDEF flag (ti.ndef). */
- } stack[TLV_MAX_DEPTH];
-};
-
-
/* Parser communication object. */
struct p12_parse_ctx_s
{
@@ -225,11 +174,6 @@ struct p12_parse_ctx_s
static int opt_verbose;
-static unsigned char *cram_octet_string (const unsigned char *input,
- size_t length, size_t *r_newlength);
-static int need_octet_string_cramming (const unsigned char *input,
- size_t length);
-
@@ -242,44 +186,6 @@ p12_set_verbosity (int verbose, int debug)
}
-#define dump_tag_info(a,b) _dump_tag_info ((a),__LINE__,(b))
-static void
-_dump_tag_info (const char *text, int lno, struct tlv_ctx_s *tlv)
-{
- struct tag_info *ti;
-
- if (opt_verbose < 2)
- return;
-
- ti = &tlv->ti;
-
- log_debug ("p12_parse:%s:%d: @%04zu class=%d tag=%lu len=%zu nhdr=%zu %s%s\n",
- text, lno,
- (size_t)(tlv->buffer - tlv->origbuffer) - ti->nhdr,
- ti->class, ti->tag, ti->length, ti->nhdr,
- ti->is_constructed?" cons":"",
- ti->ndef?" ndef":"");
-}
-
-
-#define dump_tlv_ctx(a,b,c) _dump_tlv_ctx ((a),(b),__LINE__,(c))
-static void
-_dump_tlv_ctx (const char *text, const char *text2,
- int lno, struct tlv_ctx_s *tlv)
-{
- if (opt_verbose < 2)
- return;
-
- log_debug ("p12_parse:%s%s%s:%d: @%04zu lvl=%u %s\n",
- text,
- text2? "/":"", text2? text2:"",
- lno,
- (size_t)(tlv->buffer - tlv->origbuffer),
- tlv->stacklen,
- tlv->in_ndef? " in-ndef":"");
-}
-
-
static int
digest_algo_from_oid (unsigned char const *oid, size_t oidlen)
{
@@ -398,638 +304,6 @@ builder_add_mpi (tlv_builder_t tb, int class, int tag, gcry_mpi_t mpi,
}
-
-/* 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
- * and SIZE on success. Checks that the encoded length does not
- * exhaust the length of the provided buffer. */
-static int
-parse_tag (unsigned char const **buffer, size_t *size, struct tag_info *ti)
-{
- gpg_error_t err;
- int tag;
-
- err = parse_ber_header (buffer, size,
- &ti->class, &tag,
- &ti->is_constructed, &ti->ndef,
- &ti->length, &ti->nhdr);
- if (err)
- return err;
- if (tag < 0)
- return gpg_error (GPG_ERR_EOVERFLOW);
- ti->tag = tag;
-
- if (ti->length > *size)
- return gpg_error (GPG_ERR_BUFFER_TOO_SHORT); /* data larger than buffer. */
-
- return 0;
-}
-
-
-/* Create a new TLV object. */
-static struct tlv_ctx_s *
-tlv_new (const unsigned char *buffer, size_t bufsize)
-{
- struct tlv_ctx_s *tlv;
- tlv = xtrycalloc (1, sizeof *tlv);
- if (tlv)
- {
- tlv->origbuffer = buffer;
- tlv->origbufsize = bufsize;
- tlv->buffer = buffer;
- tlv->bufsize = bufsize;
- }
- return tlv;
-}
-
-
-/* This function can be used to store a malloced buffer into the TLV
- * object. Ownership of BUFFER is thus transferred to TLV. This
- * buffer will then only be released by tlv_release. */
-static gpg_error_t
-tlv_register_buffer (struct tlv_ctx_s *tlv, char *buffer)
-{
- struct bufferlist_s *item;
-
- item = xtrycalloc (1, sizeof *item);
- if (!item)
- return gpg_error_from_syserror ();
- item->buffer = buffer;
- item->next = tlv->bufferlist;
- tlv->bufferlist = item;
- return 0;
-}
-
-
-static void
-tlv_release (struct tlv_ctx_s *tlv)
-{
- if (!tlv)
- return;
- while (tlv->bufferlist)
- {
- struct bufferlist_s *save = tlv->bufferlist->next;
- xfree (tlv->bufferlist->buffer);
- xfree (tlv->bufferlist);
- tlv->bufferlist = save;
- }
- xfree (tlv);
-}
-
-
-/* Helper for the tlv_peek functions. */
-static gpg_error_t
-_tlv_peek (struct tlv_ctx_s *tlv, struct tag_info *ti)
-{
- const unsigned char *p;
- size_t n;
-
- /* Note that we want to peek ahead of any current container but of
- * course not beyond our entire buffer. */
- p = tlv->buffer;
- if ((p - tlv->origbuffer) > tlv->origbufsize)
- return gpg_error (GPG_ERR_BUG);
- n = tlv->origbufsize - (p - tlv->origbuffer);
- return parse_tag (&p, &n, ti);
-}
-
-
-/* Look for the next tag and return true if it matches CLASS and TAG.
- * Otherwise return false. No state is changed. */
-static int
-tlv_peek (struct tlv_ctx_s *tlv, int class, int tag)
-{
- struct tag_info ti;
-
- return (!_tlv_peek (tlv, &ti)
- && ti.class == class && ti.tag == tag);
-}
-
-
-/* Look for the next tag and return true if it is the Null tag.
- * Otherwise return false. No state is changed. */
-static int
-tlv_peek_null (struct tlv_ctx_s *tlv)
-{
- struct tag_info ti;
-
- return (!_tlv_peek (tlv, &ti)
- && ti.class == CLASS_UNIVERSAL && ti.tag == TAG_NULL
- && !ti.is_constructed && !ti.length);
-}
-
-
-/* Helper for tlv_expect_sequence and tlv_expect_context_tag. */
-static gpg_error_t
-_tlv_push (struct tlv_ctx_s *tlv)
-{
- /* Right now our pointer is at the value of the current container.
- * We push that info onto the stack. */
- if (tlv->stacklen >= TLV_MAX_DEPTH)
- return (tlv->lasterr = gpg_error (GPG_ERR_TOO_MANY));
- tlv->stack[tlv->stacklen].buffer = tlv->buffer;
- tlv->stack[tlv->stacklen].bufsize = tlv->bufsize;
- tlv->stack[tlv->stacklen].in_ndef = tlv->in_ndef;
- tlv->stack[tlv->stacklen].length = tlv->ti.length;
- tlv->stacklen++;
-
- tlv->in_ndef = tlv->ti.ndef;
-
- /* We set the size of the buffer to the TLV length if it is known or
- * else to the size of the remaining entire buffer. */
- if (tlv->in_ndef)
- {
- if ((tlv->buffer - tlv->origbuffer) > tlv->origbufsize)
- return (tlv->lasterr = gpg_error (GPG_ERR_BUG));
- tlv->bufsize = tlv->origbufsize - (tlv->buffer - tlv->origbuffer);
- }
- else
- tlv->bufsize = tlv->ti.length;
-
- dump_tlv_ctx (__func__, NULL, tlv);
- return 0;
-}
-
-
-/* Helper for tlv_next. */
-static gpg_error_t
-_tlv_pop (struct tlv_ctx_s *tlv)
-{
- size_t lastlen;
-
- /* We reached the end of a container, either due to the size limit
- * or due to an end tag. Now we pop the last container so that we
- * are positioned at the value of the last container. */
- if (!tlv->stacklen)
- return gpg_error (GPG_ERR_EOF);
-
- tlv->stacklen--;
- tlv->in_ndef = tlv->stack[tlv->stacklen].in_ndef;
- if (tlv->in_ndef)
- {
- /* We keep buffer but adjust bufsize to the end of the origbuffer. */
- if ((tlv->buffer - tlv->origbuffer) > tlv->origbufsize)
- return (tlv->lasterr = gpg_error (GPG_ERR_BUG));
- tlv->bufsize = tlv->origbufsize - (tlv->buffer - tlv->origbuffer);
- }
- else
- {
- lastlen = tlv->stack[tlv->stacklen].length;
- tlv->buffer = tlv->stack[tlv->stacklen].buffer;
- tlv->bufsize = tlv->stack[tlv->stacklen].bufsize;
- if (lastlen > tlv->bufsize)
- {
- log_debug ("%s: container length larger than buffer (%zu/%zu)\n",
- __func__, lastlen, tlv->bufsize);
- return gpg_error (GPG_ERR_INV_BER);
- }
- tlv->buffer += lastlen;
- tlv->bufsize -= lastlen;
- }
-
- dump_tlv_ctx (__func__, NULL, tlv);
- return 0;
-}
-
-
-/* Parse the next tag and value. Also detect the end of a
- * container. */
-#define tlv_next(a) _tlv_next ((a), __LINE__)
-static gpg_error_t
-_tlv_next (struct tlv_ctx_s *tlv, int lno)
-{
- gpg_error_t err;
-
- tlv->lasterr = 0;
- tlv->lastfunc = __func__;
-
- if (tlv->pending)
- {
- tlv->pending = 0;
- if (opt_verbose > 1)
- log_debug ("%s: tlv_next skipped\n", __func__);
- return 0;
- }
-
- if (opt_verbose > 1)
- log_debug ("%s: tlv_next called\n", __func__);
- /* If we are at the end of an ndef container pop the stack. */
- if (!tlv->in_ndef && !tlv->bufsize)
- {
- do
- err = _tlv_pop (tlv);
- while (!err && !tlv->in_ndef && !tlv->bufsize);
- if (err)
- return (tlv->lasterr = err);
- if (opt_verbose > 1)
- log_debug ("%s: container(s) closed due to size\n", __func__);
- }
-
- again:
- /* Get the next tag. */
- err = parse_tag (&tlv->buffer, &tlv->bufsize, &tlv->ti);
- if (err)
- {
- if (opt_verbose > 1)
- log_debug ("%s: reading tag returned err=%d\n", __func__, err);
- return err;
- }
-
- /* If there is an end tag in an ndef container pop the stack. Also
- * pop other containers which are fully consumed. */
- if (tlv->in_ndef && (tlv->ti.class == CLASS_UNIVERSAL
- && !tlv->ti.tag && !tlv->ti.is_constructed))
- {
- do
- err = _tlv_pop (tlv);
- while (!err && !tlv->in_ndef && !tlv->bufsize);
- if (err)
- return (tlv->lasterr = err);
- if (opt_verbose > 1)
- log_debug ("%s: container(s) closed due to end tag\n", __func__);
- goto again;
- }
-
- _dump_tag_info (__func__, lno, tlv);
- return 0;
-}
-
-
-/* Return the current neting level of the TLV object. */
-static unsigned int
-tlv_level (struct tlv_ctx_s *tlv)
-{
- return tlv->stacklen;
-}
-
-
-/* Set a flag to indicate that the last tlv_next has not yet been
- * consumed. */
-static void
-tlv_set_pending (struct tlv_ctx_s *tlv)
-{
- tlv->pending = 1;
-}
-
-
-/* Skip over the value of the current tag. Does not yet work for ndef
- * containers. */
-static void
-tlv_skip (struct tlv_ctx_s *tlv)
-{
- tlv->lastfunc = __func__;
- log_assert (tlv->bufsize >= tlv->ti.length);
- tlv->buffer += tlv->ti.length;
- tlv->bufsize -= tlv->ti.length;
-}
-
-
-/* Expect that the current tag is a sequence and setup the context for
- * processing. */
-static gpg_error_t
-tlv_expect_sequence (struct tlv_ctx_s *tlv)
-{
- tlv->lastfunc = __func__;
- if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_SEQUENCE
- && tlv->ti.is_constructed))
- return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
- return _tlv_push (tlv);
-}
-
-
-/* Expect that the current tag is a context tag and setup the context
- * for processing. The tag of the context is returned at R_TAG. */
-static gpg_error_t
-tlv_expect_context_tag (struct tlv_ctx_s *tlv, int *r_tag)
-{
- tlv->lastfunc = __func__;
- if (!(tlv->ti.class == CLASS_CONTEXT && tlv->ti.is_constructed))
- return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
- *r_tag = tlv->ti.tag;
- return _tlv_push (tlv);
-}
-
-
-/* Expect that the current tag is a SET and setup the context for
- * processing. */
-static gpg_error_t
-tlv_expect_set (struct tlv_ctx_s *tlv)
-{
- tlv->lastfunc = __func__;
- if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_SET
- && tlv->ti.is_constructed))
- return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
- return _tlv_push (tlv);
-}
-
-
-/* Expect an object of CLASS with TAG and store its value at
- * (R_DATA,R_DATALEN). Then skip over its value to the next tag.
- * Note that the stored value is not allocated but points into
- * TLV. */
-static gpg_error_t
-tlv_expect_object (struct tlv_ctx_s *tlv, int class, int tag,
- unsigned char const **r_data, size_t *r_datalen)
-{
- gpg_error_t err;
- const unsigned char *p;
- size_t n;
- int needpush = 0;
-
- tlv->lastfunc = __func__;
- if (!(tlv->ti.class == class && tlv->ti.tag == tag))
- return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
- p = tlv->buffer;
- n = tlv->ti.length;
- if (!n && tlv->ti.ndef)
- {
- n = tlv->bufsize;
- needpush = 1;
- }
- else if (!tlv->ti.length)
- return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
-
- if (class == CLASS_CONTEXT && tag == 0 && tlv->ti.is_constructed
- && need_octet_string_cramming (p, n))
- {
- char *newbuffer;
-
- newbuffer = cram_octet_string (p, n, r_datalen);
- if (!newbuffer)
- return (tlv->lasterr = gpg_error (GPG_ERR_BAD_BER));
- err = tlv_register_buffer (tlv, newbuffer);
- if (err)
- {
- xfree (newbuffer);
- return (tlv->lasterr = err);
- }
- *r_data = newbuffer;
- }
- else
- {
- *r_data = p;
- *r_datalen = n;
- }
- if (needpush)
- return _tlv_push (tlv);
-
- if (!(tlv->bufsize >= tlv->ti.length))
- return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
- tlv->buffer += tlv->ti.length;
- tlv->bufsize -= tlv->ti.length;
- return 0;
-}
-
-
-/* Expect that the current tag is an object string and store its value
- * at (R_DATA,R_DATALEN). Then skip over its value to the next tag.
- * Note that the stored value are not allocated but point into TLV.
- * If ENCAPSULATES is set the octet string is used as a new
- * container. R_DATA and R_DATALEN are optional. */
-static gpg_error_t
-tlv_expect_octet_string (struct tlv_ctx_s *tlv, int encapsulates,
- unsigned char const **r_data, size_t *r_datalen)
-{
- gpg_error_t err;
- const unsigned char *p;
- size_t n;
-
- tlv->lastfunc = __func__;
- if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_OCTET_STRING
- && (!tlv->ti.is_constructed || encapsulates)))
- return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
- p = tlv->buffer;
- if (!(n=tlv->ti.length) && !tlv->ti.ndef)
- return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
-
- if (encapsulates && tlv->ti.is_constructed
- && need_octet_string_cramming (p, n))
- {
- char *newbuffer;
-
- newbuffer = cram_octet_string (p, n, r_datalen);
- if (!newbuffer)
- return (tlv->lasterr = gpg_error (GPG_ERR_BAD_BER));
- err = tlv_register_buffer (tlv, newbuffer);
- if (err)
- {
- xfree (newbuffer);
- return (tlv->lasterr = err);
- }
- *r_data = newbuffer;
- }
- else
- {
- if (r_data)
- *r_data = p;
- if (r_datalen)
- *r_datalen = tlv->ti.length;
- }
- if (encapsulates)
- return _tlv_push (tlv);
-
- if (!(tlv->bufsize >= tlv->ti.length))
- return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
- tlv->buffer += tlv->ti.length;
- tlv->bufsize -= tlv->ti.length;
- return 0;
-}
-
-
-/* Expect that the current tag is an integer and return its value at
- * R_VALUE. Then skip over its value to the next tag. */
-static gpg_error_t
-tlv_expect_integer (struct tlv_ctx_s *tlv, int *r_value)
-{
- const unsigned char *p;
- size_t n;
- int value;
-
- tlv->lastfunc = __func__;
- if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_INTEGER
- && !tlv->ti.is_constructed))
- return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
- p = tlv->buffer;
- if (!(n=tlv->ti.length))
- return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
-
- /* We currently support only positive values. */
- if ((*p & 0x80))
- return (tlv->lasterr = gpg_error (GPG_ERR_ERANGE));
-
- for (value = 0; n; n--)
- {
- value <<= 8;
- value |= (*p++) & 0xff;
- if (value < 0)
- return (tlv->lasterr = gpg_error (GPG_ERR_EOVERFLOW));
- }
- *r_value = value;
- if (!(tlv->bufsize >= tlv->ti.length))
- return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
- tlv->buffer += tlv->ti.length;
- tlv->bufsize -= tlv->ti.length;
- return 0;
-}
-
-
-/* Variant of tlv_expect_integer which returns an MPI. If IGNORE_ZERO
- * is set a value of 0 is ignored and R_VALUE not changed and the
- * function returns GPG_ERR_FALSE. No check for negative encoded
- * integers is doe because the old code here worked the same and we
- * can't foreclose invalid encoded PKCS#12 stuff - after all it is
- * PKCS#12 see https://www.cs.auckland.ac.nz/~pgut001/pubs/pfx.html */
-static gpg_error_t
-tlv_expect_mpinteger (struct tlv_ctx_s *tlv, int ignore_zero,
- gcry_mpi_t *r_value)
-{
- const unsigned char *p;
- size_t n;
-
- tlv->lastfunc = __func__;
- if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_INTEGER
- && !tlv->ti.is_constructed))
- return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
- p = tlv->buffer;
- if (!(n=tlv->ti.length))
- return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
-
- if (!(tlv->bufsize >= tlv->ti.length))
- return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
- tlv->buffer += tlv->ti.length;
- tlv->bufsize -= tlv->ti.length;
- if (ignore_zero && n == 1 && !*p)
- return gpg_error (GPG_ERR_FALSE);
-
- return gcry_mpi_scan (r_value, GCRYMPI_FMT_USG, p, n, NULL);
-}
-
-
-/* Expect that the current tag is an object id and store its value at
- * (R_OID,R_OIDLEN). Then skip over its value to the next tag. Note
- * that the stored value is not allocated but points into TLV. */
-static gpg_error_t
-tlv_expect_object_id (struct tlv_ctx_s *tlv,
- unsigned char const **r_oid, size_t *r_oidlen)
-{
- const unsigned char *p;
- size_t n;
-
- tlv->lastfunc = __func__;
- if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_OBJECT_ID
- && !tlv->ti.is_constructed))
- return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
- p = tlv->buffer;
- if (!(n=tlv->ti.length))
- return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
-
- *r_oid = p;
- *r_oidlen = tlv->ti.length;
- if (!(tlv->bufsize >= tlv->ti.length))
- return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
- tlv->buffer += tlv->ti.length;
- tlv->bufsize -= tlv->ti.length;
- return 0;
-}
-
-
-
-/* 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.
- *
- * The example is from Mozilla Firefox 1.0.4 which actually exports
- * certs as single byte chunks of octet strings.
- *
- * Create a new buffer with the content of that octet string. INPUT
- * is the original buffer with a LENGTH. Returns
- * NULL on error or a new malloced buffer with its actual used length
- * stored at R_NEWLENGTH. */
-static unsigned char *
-cram_octet_string (const unsigned char *input, size_t length,
- size_t *r_newlength)
-{
- 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 (length);
- if (!output)
- goto bailout;
-
- while (n)
- {
- if (parse_tag (&s, &n, &ti))
- goto bailout;
- if (ti.class == 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 == CLASS_UNIVERSAL && !ti.tag && !ti.is_constructed)
- break; /* Ready */
- else
- goto bailout;
- }
-
-
- *r_newlength = d - output;
- return output;
-
- bailout:
- gcry_free (output);
- return NULL;
-}
-
-
-/* Return true if (INPUT,LENGTH) is a structure which should be passed
- * to cram_octet_string. This is basically the same loop as in
- * cram_octet_string but without any actual copying. */
-static int
-need_octet_string_cramming (const unsigned char *input, size_t length)
-{
- const unsigned char *s = input;
- size_t n = length;
- struct tag_info ti;
-
- if (!length)
- return 0;
-
- while (n)
- {
- if (parse_tag (&s, &n, &ti))
- return 0;
- if (ti.class == CLASS_UNIVERSAL && ti.tag == TAG_OCTET_STRING
- && !ti.ndef && !ti.is_constructed)
- {
- s += ti.length;
- n -= ti.length;
- }
- else if (ti.class == CLASS_UNIVERSAL && !ti.tag && !ti.is_constructed)
- break; /* Ready */
- else
- return 0;
- }
-
- return 1;
-}
-
-
static int
string_to_key (int id, char *salt, size_t saltlen, int iter, const char *pw,
int req_keylen, unsigned char *keybuf)
@@ -1379,11 +653,11 @@ bag_decrypted_data_p (const void *plaintext, size_t length)
}
#endif /*ENABLE_DER_STRUCT_DUMPING*/
- if (parse_tag (&p, &n, &ti))
+ if (tlv_parse_tag (&p, &n, &ti))
return 0;
if (ti.class || ti.tag != TAG_SEQUENCE)
return 0;
- if (parse_tag (&p, &n, &ti))
+ if (tlv_parse_tag (&p, &n, &ti))
return 0;
return 1;
@@ -1391,7 +665,7 @@ bag_decrypted_data_p (const void *plaintext, size_t length)
static int
-parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
+parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, tlv_parser_t tlv)
{
gpg_error_t err = 0;
const char *where;
@@ -1510,13 +784,13 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
goto bailout;
if (tlv_expect_sequence (tlv))
goto bailout;
- parmlen = tlv->ti.length;
+ parmlen = tlv_parser_tag_length (tlv, 0);
if (tlv_next (tlv))
goto bailout;
if (tlv_expect_octet_string (tlv, 0, &data, &datalen))
goto bailout;
- parmlen -= tlv->ti.length + tlv->ti.nhdr;
+ parmlen -= tlv_parser_tag_length (tlv, 1);
if (datalen < 8 || datalen > sizeof salt)
{
log_info ("bad length of salt (%zu)\n", datalen);
@@ -1530,7 +804,7 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
goto bailout;
if ((err = tlv_expect_integer (tlv, &intval)))
goto bailout;
- parmlen -= tlv->ti.length + tlv->ti.nhdr;
+ parmlen -= tlv_parser_tag_length (tlv, 1);
if (!intval) /* Not a valid iteration count. */
{
err = gpg_error (GPG_ERR_INV_VALUE);
@@ -1667,7 +941,7 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
/* We do not need the TLV anymore and allocated a new one. */
where = "bag.encryptedData.decrypted-text";
- tlv = tlv_new (plain, datalen);
+ tlv = tlv_parser_new (plain, datalen, opt_verbose);
if (!tlv)
{
err = gpg_error_from_syserror ();
@@ -1688,8 +962,8 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
/* Loop over all certificates inside the bag. */
loopcount = 0;
- startlevel = tlv_level (tlv);
- while (!(err = tlv_next (tlv)) && tlv_level (tlv) == startlevel)
+ startlevel = tlv_parser_level (tlv);
+ while (!(err = tlv_next (tlv)) && tlv_parser_level (tlv) == startlevel)
{
int iscrlbag = 0;
int iskeybag = 0;
@@ -1802,8 +1076,8 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
where = "reading.keybag.key-parameters";
keyelem_count = 0;
- startlevel2 = tlv_level (tlv);
- while (!(err = tlv_next (tlv)) && tlv_level (tlv) == startlevel2)
+ startlevel2 = tlv_parser_level (tlv);
+ while (!(err = tlv_next (tlv)) && tlv_parser_level (tlv) == startlevel2)
{
if (keyelem_count >= 9)
{
@@ -1826,7 +1100,7 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
keyelem_count++;
}
if (!err)
- tlv_set_pending (tlv);
+ tlv_parser_set_pending (tlv);
else if (err && gpg_err_code (err) != GPG_ERR_EOF)
goto bailout;
err = 0;
@@ -1883,13 +1157,13 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
err = tlv_expect_set (tlv);
if (err)
goto bailout;
- tlv_skip (tlv);
+ tlv_parser_skip (tlv);
if (opt_verbose)
log_info ("skipping %s\n", where);
}
}
if (!err)
- tlv_set_pending (tlv);
+ tlv_parser_set_pending (tlv);
else if (err && gpg_err_code (err) != GPG_ERR_EOF)
{
if (!loopcount) /* The first while(tlv_next) failed. */
@@ -1900,7 +1174,7 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
leave:
if (renewed_tlv)
- tlv_release (tlv);
+ tlv_parser_release (tlv);
gcry_free (plain);
if (ctx->badpass)
{
@@ -1916,9 +1190,9 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
err = gpg_error (GPG_ERR_GENERAL);
log_error ("%s(%s): lvl=%u (%s): %s - %s\n",
__func__, where,
- tlv? tlv->stacklen : 0,
- tlv? tlv->lastfunc : "",
- tlv ? gpg_strerror (tlv->lasterr) : "init failed",
+ tlv_parser_level (tlv),
+ tlv_parser_lastfunc (tlv),
+ tlv_parser_lasterrstr (tlv),
gpg_strerror (err));
goto leave;
}
@@ -1943,9 +1217,9 @@ bag_data_p (const void *plaintext, size_t length)
}
#endif /*ENABLE_DER_STRUCT_DUMPING*/
- if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
+ if (tlv_parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
return 0;
- if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER
+ if (tlv_parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER
|| ti.length != 1 || *p)
return 0;
@@ -1954,7 +1228,7 @@ bag_data_p (const void *plaintext, size_t length)
static gpg_error_t
-parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
+parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, tlv_parser_t tlv)
{
gpg_error_t err = 0;
const char *where;
@@ -1967,7 +1241,7 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
size_t saltlen;
char iv[16];
unsigned int iter;
- struct tlv_ctx_s *saved_tlv = NULL;
+ tlv_parser_t saved_tlv = NULL;
int renewed_tlv = 0; /* True if the TLV must be released. */
unsigned char *plain = NULL;
int is_pbes2 = 0;
@@ -2039,13 +1313,13 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
goto bailout;
if (tlv_expect_sequence (tlv))
goto bailout;
- parmlen = tlv->ti.length;
+ parmlen = tlv_parser_tag_length (tlv, 0);
if (tlv_next (tlv))
goto bailout;
if (tlv_expect_octet_string (tlv, 0, &data, &datalen))
goto bailout;
- parmlen -= tlv->ti.length + tlv->ti.nhdr;
+ parmlen -= tlv_parser_tag_length (tlv, 1);
if (datalen < 8 || datalen > sizeof salt)
{
log_info ("bad length of salt (%zu) for AES\n", datalen);
@@ -2059,7 +1333,7 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
goto bailout;
if ((err = tlv_expect_integer (tlv, &intval)))
goto bailout;
- parmlen -= tlv->ti.length + tlv->ti.nhdr;
+ parmlen -= tlv_parser_tag_length (tlv, 1);
if (!intval) /* Not a valid iteration count. */
{
err = gpg_error (GPG_ERR_INV_VALUE);
@@ -2193,7 +1467,7 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
/* We do not need the TLV anymore and allocated a new one. */
where = "shrouded_key_bag.decrypted-text";
saved_tlv = tlv;
- tlv = tlv_new (plain, datalen);
+ tlv = tlv_parser_new (plain, datalen, opt_verbose);
if (!tlv)
{
err = gpg_error_from_syserror ();
@@ -2336,9 +1610,9 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
{
int keyelem_count = 0;
int firstparam = 1;
- unsigned int startlevel = tlv_level (tlv);
+ unsigned int startlevel = tlv_parser_level (tlv);
- while (!(err = tlv_next (tlv)) && tlv_level (tlv) == startlevel)
+ while (!(err = tlv_next (tlv)) && tlv_parser_level (tlv) == startlevel)
{
if (keyelem_count >= 9)
{
@@ -2365,7 +1639,7 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
firstparam = 0;
}
if (!err)
- tlv_set_pending (tlv);
+ tlv_parser_set_pending (tlv);
else if (err && gpg_err_code (err) != GPG_ERR_EOF)
goto bailout;
err = 0;
@@ -2373,7 +1647,7 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
if (opt_verbose > 1)
log_debug ("restoring parser context\n");
- tlv_release (tlv);
+ tlv_parser_release (tlv);
renewed_tlv = 0;
tlv = saved_tlv;
@@ -2386,7 +1660,7 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
err = tlv_expect_set (tlv);
if (err)
goto bailout;
- tlv_skip (tlv);
+ tlv_parser_skip (tlv);
if (opt_verbose)
log_info ("skipping %s\n", where);
}
@@ -2396,7 +1670,7 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
gcry_free (plain);
if (renewed_tlv)
{
- tlv_release (tlv);
+ tlv_parser_release (tlv);
if (opt_verbose > 1)
log_debug ("parser context released\n");
}
@@ -2405,18 +1679,18 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
bailout:
if (!err)
err = gpg_error (GPG_ERR_GENERAL);
- log_error ("%s(%s): lvl=%d (%s): %s - %s\n",
+ log_error ("%s(%s): lvl=%u (%s): %s - %s\n",
__func__, where,
- tlv? tlv->stacklen : 0,
- tlv? tlv->lastfunc : "",
- tlv ? gpg_strerror (tlv->lasterr) : "init failed",
+ tlv_parser_level (tlv),
+ tlv_parser_lastfunc (tlv),
+ tlv_parser_lasterrstr (tlv),
gpg_strerror (err));
goto leave;
}
static gpg_error_t
-parse_cert_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
+parse_cert_bag (struct p12_parse_ctx_s *ctx, tlv_parser_t tlv)
{
gpg_error_t err = 0;
const char *where;
@@ -2491,7 +1765,7 @@ parse_cert_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
err = tlv_expect_set (tlv);
if (err)
goto bailout;
- tlv_skip (tlv);
+ tlv_parser_skip (tlv);
if (opt_verbose)
log_info ("skipping %s\n", where);
}
@@ -2503,9 +1777,9 @@ parse_cert_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
bailout:
log_error ("%s(%s): lvl=%u (%s): %s - %s\n",
__func__, where,
- tlv? tlv->stacklen : 0,
- tlv? tlv->lastfunc : "",
- tlv ? gpg_strerror (tlv->lasterr) : "init failed",
+ tlv_parser_level (tlv),
+ tlv_parser_lastfunc (tlv),
+ tlv_parser_lasterrstr (tlv),
gpg_strerror (err));
if (!err)
err = gpg_error (GPG_ERR_GENERAL);
@@ -2514,7 +1788,7 @@ parse_cert_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
static gpg_error_t
-parse_bag_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
+parse_bag_data (struct p12_parse_ctx_s *ctx, tlv_parser_t tlv)
{
gpg_error_t err = 0;
const char *where;
@@ -2559,9 +1833,9 @@ parse_bag_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
if (tlv_expect_sequence (tlv))
goto bailout;
- startlevel = tlv_level (tlv);
- dump_tlv_ctx ("data.outerseqs", "beginloop", tlv);
- while (!(err = tlv_next (tlv)) && tlv_level (tlv) == startlevel)
+ startlevel = tlv_parser_level (tlv);
+ tlv_parser_dump_state ("data.outerseqs", "beginloop", tlv);
+ while (!(err = tlv_next (tlv)) && tlv_parser_level (tlv) == startlevel)
{
/* Expect:
* SEQUENCE
@@ -2595,13 +1869,13 @@ parse_bag_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
}
else
{
- tlv_skip (tlv);
+ tlv_parser_skip (tlv);
log_info ("unknown inner data type - skipped\n");
}
}
- dump_tlv_ctx ("data.outerseqs", "endloop", tlv);
+ tlv_parser_dump_state ("data.outerseqs", "endloop", tlv);
if (!err)
- tlv_set_pending (tlv);
+ tlv_parser_set_pending (tlv);
else if (err && gpg_err_code (err) != GPG_ERR_EOF)
goto bailout;
err = 0;
@@ -2612,11 +1886,11 @@ parse_bag_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
bailout:
if (!err)
err = gpg_error (GPG_ERR_GENERAL);
- log_error ("%s(%s): lvl=%d (%s): %s - %s\n",
+ log_error ("%s(%s): lvl=%u (%s): %s - %s\n",
__func__, where,
- tlv? tlv->stacklen : 0,
- tlv? tlv->lastfunc : "",
- tlv ? gpg_strerror (tlv->lasterr) : "init failed",
+ tlv_parser_level (tlv),
+ tlv_parser_lastfunc (tlv),
+ tlv_parser_lasterrstr (tlv),
gpg_strerror (err));
goto leave;
}
@@ -2636,7 +1910,7 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
{
gpg_error_t err;
const char *where = "";
- struct tlv_ctx_s *tlv;
+ tlv_parser_t tlv;
struct p12_parse_ctx_s ctx = { NULL };
const unsigned char *oid;
size_t oidlen;
@@ -2649,7 +1923,7 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
ctx.certcbarg = certcbarg;
ctx.password = pw;
- tlv = tlv_new (buffer, length);
+ tlv = tlv_parser_new (buffer, length, opt_verbose);
if (!tlv)
{
err = gpg_error_from_syserror ();
@@ -2706,12 +1980,12 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
if (tlv_expect_sequence (tlv))
goto bailout;
- startlevel = tlv_level (tlv);
- dump_tlv_ctx ("bags", "beginloop", tlv);
- while (!(err = tlv_next (tlv)) && tlv_level (tlv) == startlevel)
+ startlevel = tlv_parser_level (tlv);
+ tlv_parser_dump_state ("bags", "beginloop", tlv);
+ while (!(err = tlv_next (tlv)) && tlv_parser_level (tlv) == startlevel)
{
where = "bag-sequence";
- dump_tlv_ctx (where, NULL, tlv);
+ tlv_parser_dump_state (where, NULL, tlv);
if (tlv_expect_sequence (tlv))
goto bailout;
@@ -2744,18 +2018,18 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
}
else
{
- tlv_skip (tlv);
+ tlv_parser_skip (tlv);
log_info ("unknown outer bag type - skipped\n");
}
}
- dump_tlv_ctx ("bags", "endloop", tlv);
+ tlv_parser_dump_state ("bags", "endloop", tlv);
if (!err)
- tlv_set_pending (tlv);
+ tlv_parser_set_pending (tlv);
else if (err && gpg_err_code (err) != GPG_ERR_EOF)
goto bailout;
err = 0;
- tlv_release (tlv);
+ tlv_parser_release (tlv);
if (r_curve)
*r_curve = ctx.curve;
else
@@ -2767,10 +2041,10 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
*r_badpass = ctx.badpass;
log_error ("%s(%s): @%04zu lvl=%u %s: %s - %s\n",
__func__, where,
- tlv? (size_t)(tlv->buffer - tlv->origbuffer):0,
- tlv? tlv->stacklen : 0,
- tlv? tlv->lastfunc : "",
- tlv? gpg_strerror (tlv->lasterr) : "init failed",
+ tlv_parser_offset (tlv),
+ tlv_parser_level (tlv),
+ tlv_parser_lastfunc (tlv),
+ tlv_parser_lasterrstr (tlv),
gpg_strerror (err));
if (ctx.privatekey)
{
@@ -2781,7 +2055,7 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
gcry_free (ctx.privatekey);
ctx.privatekey = NULL;
}
- tlv_release (tlv);
+ tlv_parser_release (tlv);
gcry_free (ctx.curve);
if (r_curve)
*r_curve = NULL;