summaryrefslogtreecommitdiff
path: root/src/ber-help.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ber-help.c')
-rw-r--r--src/ber-help.c245
1 files changed, 240 insertions, 5 deletions
diff --git a/src/ber-help.c b/src/ber-help.c
index 87109f3..1b72bf0 100644
--- a/src/ber-help.c
+++ b/src/ber-help.c
@@ -36,6 +36,7 @@
#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
@@ -59,7 +60,7 @@ read_byte (ksba_reader_t reader)
static int
premature_eof (struct tag_info *ti)
{
- /* Note: We do an strcmp on this string at othyer places. */
+ /* Note: We do an strcmp on this string at other places. */
ti->err_string = "premature EOF";
return gpg_error (GPG_ERR_BAD_BER);
}
@@ -188,10 +189,13 @@ _ksba_ber_read_tl (ksba_reader_t reader, struct tag_info *ti)
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. */
+
+/* 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)
@@ -475,3 +479,234 @@ _ksba_ber_count_tl (unsigned long tag,
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;
+}