| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- /*
- * Embedded Linux library
- *
- * Copyright (C) 2017 Intel Corporation. All rights reserved.
- *
- * This 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.
- *
- * This 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 this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
- #define ASN1_ID(class, pc, tag) (((class) << 6) | ((pc) << 5) | (tag))
- #define ASN1_CLASS_UNIVERSAL 0
- #define ASN1_CLASS_CONTEXT 2
- #define ASN1_ID_SEQUENCE ASN1_ID(ASN1_CLASS_UNIVERSAL, 1, 0x10)
- #define ASN1_ID_SET ASN1_ID(ASN1_CLASS_UNIVERSAL, 1, 0x11)
- #define ASN1_ID_BOOLEAN ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x01)
- #define ASN1_ID_INTEGER ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x02)
- #define ASN1_ID_BIT_STRING ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x03)
- #define ASN1_ID_OCTET_STRING ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x04)
- #define ASN1_ID_NULL ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x05)
- #define ASN1_ID_OID ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x06)
- #define ASN1_ID_UTF8STRING ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x0c)
- #define ASN1_ID_PRINTABLESTRING ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x13)
- #define ASN1_ID_IA5STRING ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x16)
- struct asn1_oid {
- uint8_t asn1_len;
- uint8_t asn1[11];
- };
- #define asn1_oid_eq(oid1, oid2_len, oid2_string) \
- ((oid1)->asn1_len == (oid2_len) && \
- !memcmp((oid1)->asn1, (oid2_string), (oid2_len)))
- #if __STDC_VERSION__ <= 199409L
- #define inline __inline__
- #endif
- static inline int asn1_parse_definite_length(const uint8_t **buf,
- size_t *len)
- {
- int n;
- size_t result = 0;
- /* Decrease the buffer length left */
- if ((*len)-- < 1)
- return -1;
- /*
- * If short form length, move the pointer to start of data and
- * return the data length.
- */
- if (!(**buf & 0x80))
- return *(*buf)++;
- n = *(*buf)++ & 0x7f;
- if ((size_t) n > *len)
- return -1;
- *len -= n;
- while (n--)
- result = (result << 8) | *(*buf)++;
- return result;
- }
- static inline void asn1_write_definite_length(uint8_t **buf, size_t len)
- {
- int n;
- if (len < 0x80) {
- *(*buf)++ = len;
- return;
- }
- for (n = 1; len >> (n * 8); n++);
- *(*buf)++ = 0x80 | n;
- while (n--)
- *(*buf)++ = len >> (n * 8);
- }
- #define ASN1_CONTEXT_IMPLICIT(tag) (0x1000 | (tag))
- #define ASN1_CONTEXT_EXPLICIT(tag) (0x2000 | (tag))
- /*
- * Return the tag, length and value of the @index'th
- * non-context-specific-tagged element in a DER SEQUENCE or one who's
- * ASN1_CONTEXT_IMPLICIT(tag) matches @index or the inner element of
- * the one who's ASN1_CONTEXT_EXPLICIT(tag) matches @index.
- */
- static inline const uint8_t *asn1_der_find_elem(const uint8_t *buf,
- size_t len_in, int index,
- uint8_t *tag, size_t *len_out)
- {
- int n = 0;
- while (1) {
- int tlv_len;
- if (len_in < 2)
- return NULL;
- *tag = *buf++;
- len_in--;
- tlv_len = asn1_parse_definite_length((void *) &buf, &len_in);
- if (tlv_len < 0 || (size_t) tlv_len > len_in)
- return NULL;
- if (*tag >> 6 != ASN1_CLASS_CONTEXT) {
- if (n++ == index) {
- *len_out = tlv_len;
- return buf;
- }
- } else if ((*tag & 0x1f) == (index & 0xfff)) {
- /* Context-specific tag */
- if (index & 0x1000) { /* Implicit */
- *len_out = tlv_len;
- return buf;
- } else if (index & 0x2000) { /* Explicit */
- const uint8_t *outer = buf;
- int inner_len;
- if (!(*tag & 0x20)) /* Primitive */
- return NULL;
- if (tlv_len < 2)
- return NULL;
- *tag = *buf++;
- inner_len = asn1_parse_definite_length(
- (void *) &buf, &len_in);
- if (outer + tlv_len != buf + inner_len)
- return NULL;
- *len_out = inner_len;
- return buf;
- }
- }
- buf += tlv_len;
- len_in -= tlv_len;
- }
- }
- /* Return an element in a DER SEQUENCE structure by path */
- static inline const uint8_t *asn1_der_find_elem_by_path(const uint8_t *buf,
- size_t len_in, uint8_t tag,
- size_t *len_out, ...)
- {
- int index;
- va_list vl;
- va_start(vl, len_out);
- index = va_arg(vl, int);
- while (index != -1) {
- uint8_t elem_tag;
- uint8_t expect_tag;
- int prev_index = index;
- buf = asn1_der_find_elem(buf, len_in, index,
- &elem_tag, &len_in);
- if (!buf) {
- va_end(vl);
- return NULL;
- }
- index = va_arg(vl, int);
- if (prev_index & 0x1000)
- expect_tag = ASN1_ID(ASN1_CLASS_CONTEXT,
- index != -1 ? 1 :
- ((elem_tag >> 5) & 1),
- prev_index & 0xfff);
- else
- expect_tag = (index == -1) ? tag : ASN1_ID_SEQUENCE;
- if (elem_tag != expect_tag) {
- va_end(vl);
- return NULL;
- }
- }
- va_end(vl);
- *len_out = len_in;
- return buf;
- }
|