--- /dev/null
+/* asn1.h
+ *
+ * Some very limited asn.1 support.
+ */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2005 Niels Möller
+ *
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef NETTLE_ASN1_H_INCLUDED
+#define NETTLE_ASN1_H_INCLUDED
+
+#include "nettle-types.h"
+
+/* enum asn1_type keeps the class number and the constructive in bits
+ 13-14, and the constructive flag in bit 12. The remaining 14 bits
+ are the tag (although currently, only tags in the range 0-30 are
+ supported). */
+
+enum
+ {
+ ASN1_TYPE_CONSTRUCTED = 1 << 12,
+
+ ASN1_CLASS_UNIVERSAL = 0,
+ ASN1_CLASS_APPLICATION = 1 << 13,
+ ASN1_CLASS_CONTEXT_SPECIFIC = 2 << 13,
+ ASN1_CLASS_PRIVATE = 3 << 13,
+
+ ASN1_CLASS_MASK = 3 << 13,
+ ASN1_CLASS_SHIFT = 13,
+ };
+
+enum asn1_type
+ {
+ ASN1_BOOLEAN = 1,
+ ASN1_INTEGER = 2,
+ ASN1_BITSTRING = 3,
+ ASN1_OCTETSTRING = 4,
+ ASN1_NULL = 5,
+ ASN1_IDENTIFIER = 6,
+ ASN1_REAL = 9,
+ ASN1_ENUMERATED = 10,
+ ASN1_UTF8STRING = 12,
+ ASN1_SEQUENCE = 16 | ASN1_TYPE_CONSTRUCTED,
+ ASN1_SET = 17 | ASN1_TYPE_CONSTRUCTED,
+ ASN1_PRINTABLESTRING = 19,
+ ASN1_TELETEXSTRING = 20,
+ ASN1_IA5STRING = 22,
+ ASN1_UTC = 23,
+ ASN1_UNIVERSALSTRING = 28,
+ ASN1_BMPSTRING = 30,
+ };
+
+enum asn1_iterator_result
+ {
+ ASN1_ITERATOR_ERROR,
+ ASN1_ITERATOR_PRIMITIVE,
+ ASN1_ITERATOR_CONSTRUCTED,
+ ASN1_ITERATOR_END,
+ };
+
+/* Parsing DER objects. */
+struct asn1_der_iterator
+{
+ unsigned buffer_length;
+ const uint8_t *buffer;
+
+ /* Next object to parse. */
+ unsigned pos;
+
+ enum asn1_type type;
+
+ /* Pointer to the current object */
+ unsigned length;
+ const uint8_t *data;
+};
+
+/* Initializes the iterator. */
+enum asn1_iterator_result
+asn1_der_iterator_first(struct asn1_der_iterator *iterator,
+ unsigned length, const uint8_t *input);
+
+enum asn1_iterator_result
+asn1_der_iterator_next(struct asn1_der_iterator *iterator);
+
+/* Starts parsing of a constructed object. */
+enum asn1_iterator_result
+asn1_der_decode_constructed(struct asn1_der_iterator *i,
+ struct asn1_der_iterator *contents);
+
+/* All these functions return 1 on success, 0 on failure */
+int
+asn1_der_get_uint32(struct asn1_der_iterator *i,
+ uint32_t *x);
+
+#endif /* NETTLE_ASN1_H_INCLUDED */
--- /dev/null
+/* der-iterator.c
+ *
+ * Parses DER encoded objects.
+ */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2005 Niels Möller
+ *
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#if HAVE_LIBGMP
+#include "bignum.h"
+#endif
+
+#include "asn1.h"
+
+#include "macros.h"
+
+/* Basic DER syntax: (reference: A Layman's Guide to a Subset of ASN.1, BER, and DER,
+ http://luca.ntop.org/Teaching/Appunti/asn1.html)
+
+ The DER header contains a tag and a length. First, the tag. cls is
+ the class number, c is one if the object is "constructed" and zero
+ if it is primitive. The tag is represented either using a single
+ byte,
+
+ 7 6 5 4 3 2 1 0
+ _____________________
+ |_cls_|_c_|_______tag_| 0 <= tag <= 30
+
+ or multiple bytes
+
+ 7 6 5 4 3 2 1 0
+ _____________________
+ |_cls_|_c_|_1_1_1_1_1_|
+
+ followed by the real tag number, in base 128, with all but the
+ final byte having the most significant bit set. The tag must be
+ represented with as few bytes as possible. High tag numbers are
+ currently *not* supported.
+
+ Next, the length, either a single byte with the most significant bit clear, or
+
+ 7 6 5 4 3 2 1 0
+ _________________
+ |_1_|___________k_|
+
+ followed by k additional bytes that gice the length, in network
+ byte order. The length must be encoded using as few bytes as
+ possible, and k = 0 is reserved for the "indefinite length form"
+ which is not supported.
+
+ After the length comes the contets. For primitive objects (c == 0),
+ it's depends on the type. For constructed objects, it's a
+ concatenation of the DER encodings of zero or more other objects.
+*/
+
+enum {
+ TAG_MASK = 0x1f,
+ CLASS_MASK = 0xc0,
+ CONSTRUCTED_MASK = 0x20,
+};
+
+/* Initializes the iterator, but one has to call next to get to the
+ * first element. */
+static void
+asn1_der_iterator_init(struct asn1_der_iterator *iterator,
+ unsigned length, const uint8_t *input)
+{
+ iterator->buffer_length = length;
+ iterator->buffer = input;
+ iterator->pos = 0;
+ iterator->type = 0;
+}
+
+#define LEFT(i) ((i)->buffer_length - (i)->pos)
+#define NEXT(i) ((i)->buffer[(i)->pos++])
+
+/* Gets type and length of the next object. */
+enum asn1_iterator_result
+asn1_der_iterator_next(struct asn1_der_iterator *i)
+{
+ uint8_t tag;
+
+ if (!LEFT(i))
+ return ASN1_ITERATOR_END;
+
+ tag = NEXT(i);
+ if (!LEFT(i))
+ return ASN1_ITERATOR_ERROR;
+
+ if ( (tag & TAG_MASK) == TAG_MASK)
+ {
+ /* FIXME: Long tags not supported */
+ return ASN1_ITERATOR_ERROR;
+ }
+
+ i->length = NEXT(i);
+ if (i->length & 0x80)
+ {
+ /* FIXME: Large objects not yet supported. */
+ return ASN1_ITERATOR_ERROR;
+ }
+ if (LEFT(i) < i->length)
+ return ASN1_ITERATOR_ERROR;
+
+ i->data = i->buffer + i->pos;
+ i->pos += i->length;
+
+ i->type = tag & TAG_MASK;
+ i->type |= (tag & CLASS_MASK) << (ASN1_CLASS_SHIFT - 6);
+ if (tag & CONSTRUCTED_MASK)
+ {
+ i->type |= ASN1_TYPE_CONSTRUCTED;
+ return ASN1_ITERATOR_CONSTRUCTED;
+ }
+ else
+ return ASN1_ITERATOR_PRIMITIVE;
+}
+
+enum asn1_iterator_result
+asn1_der_iterator_first(struct asn1_der_iterator *i,
+ unsigned length, const uint8_t *input)
+{
+ asn1_der_iterator_init(i, length, input);
+ return asn1_der_iterator_next(i);
+}
+
+enum asn1_iterator_result
+asn1_der_decode_constructed(struct asn1_der_iterator *i,
+ struct asn1_der_iterator *contents)
+{
+ assert(i->type & ASN1_TYPE_CONSTRUCTED);
+ return asn1_der_iterator_first(contents, i->length, i->data);
+}
+
+int
+asn1_der_get_uint32(struct asn1_der_iterator *i,
+ uint32_t *x)
+{
+ /* Big endian, two's complement, minimum number of octets (except 0,
+ which is encoded as a single octet */
+ uint32_t value = 0;
+ unsigned length = i->length;
+ unsigned k;
+
+ if (!length || length > 5)
+ return 0;
+
+ if (i->data[length - 1] >= 0x80)
+ /* Signed number */
+ return 0;
+
+ if (length > 1
+ && i->data[length -1] == 0
+ && i->data[length -2] < 0x80)
+ /* Non-minimal number of digits */
+ return 0;
+
+ if (length == 5)
+ {
+ if (i->data[4])
+ return 0;
+ length--;
+ }
+
+ for (value = k = 0; k < length; k++)
+ value = (value << 8) | i->data[k];
+
+ *x = value;
+ return 1;
+}
+
+#if HAVE_LIBGMP
+int
+asn1_der_get_bignum(struct asn1_der_iterator *i,
+ mpz_t x, unsigned limit)
+{
+ /* Allow some extra here, for leading sign octets. */
+ if (limit && (8 * i->length > (16 + limit)))
+ return 0;
+
+ nettle_mpz_set_str_256_s(x, i->length, i->data);
+
+ /* FIXME: How to interpret a limit for negative numbers? */
+ if (limit && mpz_sizeinbase(x, 2) > limit)
+ return 0;
+
+ return 1;
+}
+#endif /* HAVE_LIBGMP */