From c87cc07a752d7712f1574046e0ee8bfc72280ae8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20M=C3=B6ller?= <nisse@lysator.liu.se>
Date: Sun, 13 Nov 2005 21:09:13 +0100
Subject: [PATCH] * der-iterator.c: New file. * asn1.h: New file.

Rev: src/nettle/asn1.h:1.1
Rev: src/nettle/der-iterator.c:1.1
---
 asn1.h         | 112 ++++++++++++++++++++++++++
 der-iterator.c | 212 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 324 insertions(+)
 create mode 100644 asn1.h
 create mode 100644 der-iterator.c

diff --git a/asn1.h b/asn1.h
new file mode 100644
index 00000000..4c73d046
--- /dev/null
+++ b/asn1.h
@@ -0,0 +1,112 @@
+/* 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 */
diff --git a/der-iterator.c b/der-iterator.c
new file mode 100644
index 00000000..4a7961c9
--- /dev/null
+++ b/der-iterator.c
@@ -0,0 +1,212 @@
+/* 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 */
-- 
GitLab