Page MenuHome GnuPG

No OneTemporary

diff --git a/src/ber-help.c b/src/ber-help.c
index 81c31ed..56efb6a 100644
--- a/src/ber-help.c
+++ b/src/ber-help.c
@@ -1,713 +1,719 @@
/* ber-help.c - BER herlper functions
* Copyright (C) 2001, 2012 g10 Code GmbH
*
* This file is part of KSBA.
*
* KSBA is free software; you can redistribute it and/or modify
* it under the terms of either
*
* - the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at
* your option) any later version.
*
* or
*
* - the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* or both in parallel, as here.
*
* KSBA is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copies of the GNU General Public License
* and the GNU Lesser General Public License along with this program;
* if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "util.h"
#include "asn1-func.h" /* need some constants */
#include "convert.h"
#include "ber-help.h"
/* Fixme: The parser functions should check that primitive types don't
have the constructed bit set (which is not allowed). This saves us
some work when using these parsers */
static int
read_byte (ksba_reader_t reader)
{
unsigned char buf;
size_t nread;
int rc;
do
rc = ksba_reader_read (reader, &buf, 1, &nread);
while (!rc && !nread);
return rc? -1: buf;
}
static int
premature_eof (struct tag_info *ti)
{
/* Note: We do an strcmp on this string at other places. */
ti->err_string = "premature EOF";
return gpg_error (GPG_ERR_BAD_BER);
}
static gpg_error_t
eof_or_error (ksba_reader_t reader, struct tag_info *ti, int premature)
{
gpg_error_t err;
err = ksba_reader_error (reader);
if (err)
{
ti->err_string = "read error";
return err;
}
if (premature)
return premature_eof (ti);
return gpg_error (GPG_ERR_EOF);
}
/*
Read the tag and the length part from the TLV triplet.
*/
gpg_error_t
_ksba_ber_read_tl (ksba_reader_t reader, struct tag_info *ti)
{
int c;
unsigned long tag;
ti->length = 0;
ti->ndef = 0;
ti->nhdr = 0;
ti->err_string = NULL;
ti->non_der = 0;
/* Get the tag */
c = read_byte (reader);
if (c==-1)
return eof_or_error (reader, ti, 0);
ti->buf[ti->nhdr++] = c;
ti->class = (c & 0xc0) >> 6;
ti->is_constructed = !!(c & 0x20);
tag = c & 0x1f;
if (tag == 0x1f)
{
tag = 0;
do
{
/* We silently ignore an overflow in the tag value. It is
not worth checking for it. */
tag <<= 7;
c = read_byte (reader);
if (c == -1)
return eof_or_error (reader, ti, 1);
if (ti->nhdr >= DIM (ti->buf))
{
ti->err_string = "tag+length header too large";
return gpg_error (GPG_ERR_BAD_BER);
}
ti->buf[ti->nhdr++] = c;
tag |= c & 0x7f;
}
while (c & 0x80);
}
ti->tag = tag;
/* Get the length */
c = read_byte (reader);
if (c == -1)
return eof_or_error (reader, ti, 1);
if (ti->nhdr >= DIM (ti->buf))
{
ti->err_string = "tag+length header too large";
return gpg_error (GPG_ERR_BAD_BER);
}
ti->buf[ti->nhdr++] = c;
if ( !(c & 0x80) )
ti->length = c;
else if (c == 0x80)
{
ti->ndef = 1;
ti->non_der = 1;
}
else if (c == 0xff)
{
ti->err_string = "forbidden length value";
return gpg_error (GPG_ERR_BAD_BER);
}
else
{
unsigned long len = 0;
int count = c & 0x7f;
if (count > sizeof (len) || count > sizeof (size_t))
return gpg_error (GPG_ERR_BAD_BER);
for (; count; count--)
{
len <<= 8;
c = read_byte (reader);
if (c == -1)
return eof_or_error (reader, ti, 1);
if (ti->nhdr >= DIM (ti->buf))
{
ti->err_string = "tag+length header too large";
return gpg_error (GPG_ERR_BAD_BER);
}
ti->buf[ti->nhdr++] = c;
len |= c & 0xff;
}
ti->length = len;
}
+ if (ti->length > ti->nhdr && (ti->nhdr + ti->length) < ti->length)
+ {
+ ti->err_string = "header+length would overflow";
+ return gpg_error (GPG_ERR_EOVERFLOW);
+ }
+
/* Without this kludge some example certs can't be parsed */
if (ti->class == CLASS_UNIVERSAL && !ti->tag)
ti->length = 0;
return 0;
}
/* Parse the buffer at the address BUFFER which of SIZE and return the
* tag and the length part from the TLV triplet. Update BUFFER and
* SIZE on success. Note that this function will never return
* GPG_ERR_INV_OBJ so that this error code can be used by the parse_foo
* functions below to return an error for unexpected tags and the
* caller is able to backoff in that case. */
gpg_error_t
_ksba_ber_parse_tl (unsigned char const **buffer, size_t *size,
struct tag_info *ti)
{
int c;
unsigned long tag;
const unsigned char *buf = *buffer;
size_t length = *size;
ti->length = 0;
ti->ndef = 0;
ti->nhdr = 0;
ti->err_string = NULL;
ti->non_der = 0;
/* Get the tag */
if (!length)
return premature_eof (ti);
c = *buf++; length--;
ti->buf[ti->nhdr++] = c;
ti->class = (c & 0xc0) >> 6;
ti->is_constructed = !!(c & 0x20);
tag = c & 0x1f;
if (tag == 0x1f)
{
tag = 0;
do
{
/* We silently ignore an overflow in the tag value. It is
not worth checking for it. */
tag <<= 7;
if (!length)
return premature_eof (ti);
c = *buf++; length--;
if (ti->nhdr >= DIM (ti->buf))
{
ti->err_string = "tag+length header too large";
return gpg_error (GPG_ERR_BAD_BER);
}
ti->buf[ti->nhdr++] = c;
tag |= c & 0x7f;
}
while (c & 0x80);
}
ti->tag = tag;
/* Get the length */
if (!length)
return premature_eof (ti);
c = *buf++; length--;
if (ti->nhdr >= DIM (ti->buf))
{
ti->err_string = "tag+length header too large";
return gpg_error (GPG_ERR_BAD_BER);
}
ti->buf[ti->nhdr++] = c;
if ( !(c & 0x80) )
ti->length = c;
else if (c == 0x80)
{
ti->ndef = 1;
ti->non_der = 1;
}
else if (c == 0xff)
{
ti->err_string = "forbidden length value";
return gpg_error (GPG_ERR_BAD_BER);
}
else
{
unsigned long len = 0;
int count = c & 0x7f;
if (count > sizeof (len) || count > sizeof (size_t))
return gpg_error (GPG_ERR_BAD_BER);
for (; count; count--)
{
len <<= 8;
if (!length)
return premature_eof (ti);
c = *buf++; length--;
if (ti->nhdr >= DIM (ti->buf))
{
ti->err_string = "tag+length header too large";
return gpg_error (GPG_ERR_BAD_BER);
}
ti->buf[ti->nhdr++] = c;
len |= c & 0xff;
}
/* Sanity check for the length: This is done so that we can take
* the value for malloc plus some additional bytes without
* risking an overflow. */
if (len > (1 << 30))
return gpg_error (GPG_ERR_BAD_BER);
ti->length = len;
}
/* Without this kludge some example certs can't be parsed */
if (ti->class == CLASS_UNIVERSAL && !ti->tag)
ti->length = 0;
*buffer = buf;
*size = length;
return 0;
}
/* Write TAG of CLASS to WRITER. constructed is a flag telling
whether the value is a constructed one. length gives the length of
the value, if it is 0 undefinite length is assumed. length is
ignored for the NULL tag. */
gpg_error_t
_ksba_ber_write_tl (ksba_writer_t writer,
unsigned long tag,
enum tag_class class,
int constructed,
unsigned long length)
{
unsigned char buf[50];
int buflen = 0;
if (tag < 0x1f)
{
*buf = (class << 6) | tag;
if (constructed)
*buf |= 0x20;
buflen++;
}
else
{
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
}
if (!tag && !class)
buf[buflen++] = 0; /* end tag */
else if (tag == TYPE_NULL && !class)
buf[buflen++] = 0; /* NULL tag */
else if (!length)
buf[buflen++] = 0x80; /* indefinite length */
else if (length < 128)
buf[buflen++] = length;
else
{
int i;
/* fixme: if we know the sizeof an ulong we could support larger
objects - however this is pretty ridiculous */
i = (length <= 0xff ? 1:
length <= 0xffff ? 2:
length <= 0xffffff ? 3: 4);
buf[buflen++] = (0x80 | i);
if (i > 3)
buf[buflen++] = length >> 24;
if (i > 2)
buf[buflen++] = length >> 16;
if (i > 1)
buf[buflen++] = length >> 8;
buf[buflen++] = length;
}
return ksba_writer_write (writer, buf, buflen);
}
/* Encode TAG of CLASS in BUFFER. CONSTRUCTED is a flag telling
whether the value is a constructed one. LENGTH gives the length of
the value, if it is 0 undefinite length is assumed. LENGTH is
ignored for the NULL tag. It is assumed that the provide buffer is
large enough for storing the result - this is usually achieved by
using _ksba_ber_count_tl() in advance. Returns 0 in case of an
error or the length of the encoding.*/
size_t
_ksba_ber_encode_tl (unsigned char *buffer,
unsigned long tag,
enum tag_class class,
int constructed,
unsigned long length)
{
unsigned char *buf = buffer;
if (tag < 0x1f)
{
*buf = (class << 6) | tag;
if (constructed)
*buf |= 0x20;
buf++;
}
else
{
return 0; /*Not implemented*/
}
if (!tag && !class)
*buf++ = 0; /* end tag */
else if (tag == TYPE_NULL && !class)
*buf++ = 0; /* NULL tag */
else if (!length)
*buf++ = 0x80; /* indefinite length */
else if (length < 128)
*buf++ = length;
else
{
int i;
/* fixme: if we know the sizeof an ulong we could support larger
objetcs - however this is pretty ridiculous */
i = (length <= 0xff ? 1:
length <= 0xffff ? 2:
length <= 0xffffff ? 3: 4);
*buf++ = (0x80 | i);
if (i > 3)
*buf++ = length >> 24;
if (i > 2)
*buf++ = length >> 16;
if (i > 1)
*buf++ = length >> 8;
*buf++ = length;
}
return buf - buffer;
}
/* Calculate the length of the TL needed to encode a TAG of CLASS.
CONSTRUCTED is a flag telling whether the value is a constructed
one. LENGTH gives the length of the value; if it is 0 an
indefinite length is assumed. LENGTH is ignored for the NULL
tag. */
size_t
_ksba_ber_count_tl (unsigned long tag,
enum tag_class class,
int constructed,
unsigned long length)
{
int buflen = 0;
(void)constructed; /* Not used, but passed for uniformity of such calls. */
/* coverity[identical_branches] */
if (tag < 0x1f)
{
buflen++;
}
else
{
buflen++; /* assume one and let the actual write function bail out */
}
if (!tag && !class)
buflen++; /* end tag */
else if (tag == TYPE_NULL && !class)
buflen++; /* NULL tag */
else if (!length)
buflen++; /* indefinite length */
else if (length < 128)
buflen++;
else
{
int i;
/* fixme: if we know the sizeof an ulong we could support larger
objetcs - however this is pretty ridiculous */
i = (length <= 0xff ? 1:
length <= 0xffff ? 2:
length <= 0xffffff ? 3: 4);
buflen++;
if (i > 3)
buflen++;
if (i > 2)
buflen++;
if (i > 1)
buflen++;
buflen++;
}
return buflen;
}
gpg_error_t
_ksba_parse_sequence (unsigned char const **buf, size_t *len,
struct tag_info *ti)
{
gpg_error_t err;
err = _ksba_ber_parse_tl (buf, len, ti);
if (err)
;
else if (!(ti->class == CLASS_UNIVERSAL && ti->tag == TYPE_SEQUENCE
&& ti->is_constructed) )
err = gpg_error (GPG_ERR_INV_OBJ);
else if (ti->length > *len)
err = gpg_error (GPG_ERR_BAD_BER);
return err;
}
/* Note that this function returns GPG_ERR_FALSE if the TLV is valid
* but the tag does not match. The caller may thus check for this
* error code and compare against other tag values. */
gpg_error_t
_ksba_parse_context_tag (unsigned char const **buf, size_t *len,
struct tag_info *ti, int tag)
{
gpg_error_t err;
err = _ksba_ber_parse_tl (buf, len, ti);
if (err)
;
else if (!(ti->class == CLASS_CONTEXT && ti->is_constructed))
err = gpg_error (GPG_ERR_INV_OBJ);
else if (ti->length > *len)
err = gpg_error (GPG_ERR_BAD_BER);
else if (ti->tag != tag)
err = gpg_error (GPG_ERR_FALSE);
return err;
}
gpg_error_t
_ksba_parse_enumerated (unsigned char const **buf, size_t *len,
struct tag_info *ti, size_t maxlen)
{
gpg_error_t err;
err = _ksba_ber_parse_tl (buf, len, ti);
if (err)
;
else if (!(ti->class == CLASS_UNIVERSAL && ti->tag == TYPE_ENUMERATED
&& !ti->is_constructed) )
err = gpg_error (GPG_ERR_INV_OBJ);
else if (!ti->length)
err = gpg_error (GPG_ERR_TOO_SHORT);
else if (maxlen && ti->length > maxlen)
err = gpg_error (GPG_ERR_TOO_LARGE);
else if (ti->length > *len)
err = gpg_error (GPG_ERR_BAD_BER);
return err;
}
gpg_error_t
_ksba_parse_integer (unsigned char const **buf, size_t *len,
struct tag_info *ti)
{
gpg_error_t err;
err = _ksba_ber_parse_tl (buf, len, ti);
if (err)
;
else if (!(ti->class == CLASS_UNIVERSAL && ti->tag == TYPE_INTEGER
&& !ti->is_constructed) )
err = gpg_error (GPG_ERR_INV_OBJ);
else if (!ti->length)
err = gpg_error (GPG_ERR_TOO_SHORT);
else if (ti->length > *len)
err = gpg_error (GPG_ERR_BAD_BER);
return err;
}
gpg_error_t
_ksba_parse_octet_string (unsigned char const **buf, size_t *len,
struct tag_info *ti)
{
gpg_error_t err;
err= _ksba_ber_parse_tl (buf, len, ti);
if (err)
;
else if (!(ti->class == CLASS_UNIVERSAL && ti->tag == TYPE_OCTET_STRING
&& !ti->is_constructed) )
err = gpg_error (GPG_ERR_INV_OBJ);
else if (!ti->length)
err = gpg_error (GPG_ERR_TOO_SHORT);
else if (ti->length > *len)
err = gpg_error (GPG_ERR_BAD_BER);
return err;
}
/* Note that R_BOOL will only be set if a value has been given. Thus
the caller should set it to the default value prior to calling this
function. Obviously no call to parse_skip is required after
calling this function. */
gpg_error_t
_ksba_parse_optional_boolean (unsigned char const **buf, size_t *len,
int *r_bool)
{
gpg_error_t err;
struct tag_info ti;
err = _ksba_ber_parse_tl (buf, len, &ti);
if (err)
;
else if (!ti.length)
err = gpg_error (GPG_ERR_TOO_SHORT);
else if (ti.length > *len)
err = gpg_error (GPG_ERR_BAD_BER);
else if (ti.class == CLASS_UNIVERSAL && ti.tag == TYPE_BOOLEAN
&& !ti.is_constructed)
{
if (ti.length != 1)
err = gpg_error (GPG_ERR_BAD_BER);
*r_bool = !!**buf;
parse_skip (buf, len, &ti);
}
else
{ /* Undo the read. */
*buf -= ti.nhdr;
*len += ti.nhdr;
}
return err;
}
/* Parse an optional Null tag. Ir R_SEEN is not NULL it is set to
* true if a NULL tag was encountered. */
gpg_error_t
_ksba_parse_optional_null (unsigned char const **buf, size_t *len,
int *r_seen)
{
gpg_error_t err;
struct tag_info ti;
if (r_seen)
*r_seen = 0;
err = _ksba_ber_parse_tl (buf, len, &ti);
if (err)
;
else if (ti.length > *len)
err = gpg_error (GPG_ERR_BAD_BER);
else if (ti.class == CLASS_UNIVERSAL && ti.tag == TYPE_NULL
&& !ti.is_constructed)
{
if (ti.length)
err = gpg_error (GPG_ERR_BAD_BER);
if (r_seen)
*r_seen = 1;
parse_skip (buf, len, &ti);
}
else
{ /* Undo the read. */
*buf -= ti.nhdr;
*len += ti.nhdr;
}
return err;
}
gpg_error_t
_ksba_parse_object_id_into_str (unsigned char const **buf, size_t *len,
char **oid)
{
struct tag_info ti;
gpg_error_t err;
*oid = NULL;
err = _ksba_ber_parse_tl (buf, len, &ti);
if (err)
;
else if (!(ti.class == CLASS_UNIVERSAL && ti.tag == TYPE_OBJECT_ID
&& !ti.is_constructed) )
err = gpg_error (GPG_ERR_INV_OBJ);
else if (!ti.length)
err = gpg_error (GPG_ERR_TOO_SHORT);
else if (ti.length > *len)
err = gpg_error (GPG_ERR_BAD_BER);
else if (!(*oid = ksba_oid_to_str (*buf, ti.length)))
err = gpg_error_from_syserror ();
else
{
*buf += ti.length;
*len -= ti.length;
}
return err;
}
gpg_error_t
_ksba_parse_asntime_into_isotime (unsigned char const **buf, size_t *len,
ksba_isotime_t isotime)
{
struct tag_info ti;
gpg_error_t err;
err = _ksba_ber_parse_tl (buf, len, &ti);
if (err)
;
else if ( !(ti.class == CLASS_UNIVERSAL
&& (ti.tag == TYPE_UTC_TIME || ti.tag == TYPE_GENERALIZED_TIME)
&& !ti.is_constructed) )
err = gpg_error (GPG_ERR_INV_OBJ);
else if (ti.length > *len)
err = gpg_error (GPG_ERR_INV_BER);
else if (!(err = _ksba_asntime_to_iso (*buf, ti.length,
ti.tag == TYPE_UTC_TIME, isotime)))
parse_skip (buf, len, &ti);
return err;
}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Dec 23, 5:14 PM (1 h, 48 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
06/fd/c93601644b142b30d02180538c06

Event Timeline