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