You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
8934 lines
237 KiB
8934 lines
237 KiB
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
|
From: Daniel Axtens <dja@axtens.net> |
|
Date: Wed, 10 Jun 2020 16:31:22 +1000 |
|
Subject: [PATCH] libtasn1: import libtasn1-4.16.0 |
|
|
|
Import a very trimmed-down set of libtasn1 files: |
|
|
|
pushd /tmp |
|
wget https://ftp.gnu.org/gnu/libtasn1/libtasn1-4.16.0.tar.gz |
|
popd |
|
pushd grub-core/lib |
|
mkdir libtasn1 |
|
cp /tmp/libtasn1-4.16.0/{README.md,LICENSE} libtasn1/ |
|
mkdir libtasn1/lib |
|
cp /tmp/libtasn1-4.16.0/lib/{coding.c,decoding.c,element.c,element.h,errors.c,gstr.c,gstr.h,int.h,parser_aux.c,parser_aux.h,structure.c,structure.h} libtasn1/lib |
|
cp /tmp/libtasn1-4.16.0/lib/includes/libtasn1.h ../../include/grub/ |
|
git add libtasn1/ ../../include/grub/libtasn1.h |
|
popd |
|
|
|
Signed-off-by: Daniel Axtens <dja@axtens.net> |
|
--- |
|
grub-core/lib/libtasn1/lib/coding.c | 1415 ++++++++++++++++++ |
|
grub-core/lib/libtasn1/lib/decoding.c | 2478 +++++++++++++++++++++++++++++++ |
|
grub-core/lib/libtasn1/lib/element.c | 1111 ++++++++++++++ |
|
grub-core/lib/libtasn1/lib/errors.c | 100 ++ |
|
grub-core/lib/libtasn1/lib/gstr.c | 74 + |
|
grub-core/lib/libtasn1/lib/parser_aux.c | 1173 +++++++++++++++ |
|
grub-core/lib/libtasn1/lib/structure.c | 1220 +++++++++++++++ |
|
grub-core/lib/libtasn1/lib/element.h | 40 + |
|
grub-core/lib/libtasn1/lib/gstr.h | 47 + |
|
grub-core/lib/libtasn1/lib/int.h | 221 +++ |
|
grub-core/lib/libtasn1/lib/parser_aux.h | 172 +++ |
|
grub-core/lib/libtasn1/lib/structure.h | 45 + |
|
include/grub/libtasn1.h | 588 ++++++++ |
|
grub-core/lib/libtasn1/LICENSE | 16 + |
|
grub-core/lib/libtasn1/README.md | 91 ++ |
|
15 files changed, 8791 insertions(+) |
|
create mode 100644 grub-core/lib/libtasn1/lib/coding.c |
|
create mode 100644 grub-core/lib/libtasn1/lib/decoding.c |
|
create mode 100644 grub-core/lib/libtasn1/lib/element.c |
|
create mode 100644 grub-core/lib/libtasn1/lib/errors.c |
|
create mode 100644 grub-core/lib/libtasn1/lib/gstr.c |
|
create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.c |
|
create mode 100644 grub-core/lib/libtasn1/lib/structure.c |
|
create mode 100644 grub-core/lib/libtasn1/lib/element.h |
|
create mode 100644 grub-core/lib/libtasn1/lib/gstr.h |
|
create mode 100644 grub-core/lib/libtasn1/lib/int.h |
|
create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.h |
|
create mode 100644 grub-core/lib/libtasn1/lib/structure.h |
|
create mode 100644 include/grub/libtasn1.h |
|
create mode 100644 grub-core/lib/libtasn1/LICENSE |
|
create mode 100644 grub-core/lib/libtasn1/README.md |
|
|
|
diff --git a/grub-core/lib/libtasn1/lib/coding.c b/grub-core/lib/libtasn1/lib/coding.c |
|
new file mode 100644 |
|
index 00000000000..245ea64cf0a |
|
--- /dev/null |
|
+++ b/grub-core/lib/libtasn1/lib/coding.c |
|
@@ -0,0 +1,1415 @@ |
|
+/* |
|
+ * Copyright (C) 2002-2014 Free Software Foundation, Inc. |
|
+ * |
|
+ * This file is part of LIBTASN1. |
|
+ * |
|
+ * The LIBTASN1 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 Street, Fifth Floor, Boston, MA |
|
+ * 02110-1301, USA |
|
+ */ |
|
+ |
|
+ |
|
+/*****************************************************/ |
|
+/* File: coding.c */ |
|
+/* Description: Functions to create a DER coding of */ |
|
+/* an ASN1 type. */ |
|
+/*****************************************************/ |
|
+ |
|
+#include <int.h> |
|
+#include "parser_aux.h" |
|
+#include <gstr.h> |
|
+#include "element.h" |
|
+#include "minmax.h" |
|
+#include <structure.h> |
|
+ |
|
+#define MAX_TAG_LEN 16 |
|
+ |
|
+/******************************************************/ |
|
+/* Function : _asn1_error_description_value_not_found */ |
|
+/* Description: creates the ErrorDescription string */ |
|
+/* for the ASN1_VALUE_NOT_FOUND error. */ |
|
+/* Parameters: */ |
|
+/* node: node of the tree where the value is NULL. */ |
|
+/* ErrorDescription: string returned. */ |
|
+/* Return: */ |
|
+/******************************************************/ |
|
+static void |
|
+_asn1_error_description_value_not_found (asn1_node node, |
|
+ char *ErrorDescription) |
|
+{ |
|
+ |
|
+ if (ErrorDescription == NULL) |
|
+ return; |
|
+ |
|
+ Estrcpy (ErrorDescription, ":: value of element '"); |
|
+ _asn1_hierarchical_name (node, ErrorDescription + strlen (ErrorDescription), |
|
+ ASN1_MAX_ERROR_DESCRIPTION_SIZE - 40); |
|
+ Estrcat (ErrorDescription, "' not found"); |
|
+ |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_length_der: |
|
+ * @len: value to convert. |
|
+ * @der: buffer to hold the returned encoding (may be %NULL). |
|
+ * @der_len: number of meaningful bytes of ANS (der[0]..der[der_len-1]). |
|
+ * |
|
+ * Creates the DER encoding of the provided length value. |
|
+ * The @der buffer must have enough room for the output. The maximum |
|
+ * length this function will encode is %ASN1_MAX_LENGTH_SIZE. |
|
+ * |
|
+ * To know the size of the DER encoding use a %NULL value for @der. |
|
+ **/ |
|
+void |
|
+asn1_length_der (unsigned long int len, unsigned char *der, int *der_len) |
|
+{ |
|
+ int k; |
|
+ unsigned char temp[ASN1_MAX_LENGTH_SIZE]; |
|
+#if SIZEOF_UNSIGNED_LONG_INT > 8 |
|
+ len &= 0xFFFFFFFFFFFFFFFF; |
|
+#endif |
|
+ |
|
+ if (len < 128) |
|
+ { |
|
+ /* short form */ |
|
+ if (der != NULL) |
|
+ der[0] = (unsigned char) len; |
|
+ *der_len = 1; |
|
+ } |
|
+ else |
|
+ { |
|
+ /* Long form */ |
|
+ k = 0; |
|
+ while (len) |
|
+ { |
|
+ temp[k++] = len & 0xFF; |
|
+ len = len >> 8; |
|
+ } |
|
+ *der_len = k + 1; |
|
+ if (der != NULL) |
|
+ { |
|
+ der[0] = ((unsigned char) k & 0x7F) + 128; |
|
+ while (k--) |
|
+ der[*der_len - 1 - k] = temp[k]; |
|
+ } |
|
+ } |
|
+} |
|
+ |
|
+/******************************************************/ |
|
+/* Function : _asn1_tag_der */ |
|
+/* Description: creates the DER coding for the CLASS */ |
|
+/* and TAG parameters. */ |
|
+/* It is limited by the ASN1_MAX_TAG_SIZE variable */ |
|
+/* Parameters: */ |
|
+/* class: value to convert. */ |
|
+/* tag_value: value to convert. */ |
|
+/* ans: string returned. */ |
|
+/* ans_len: number of meaningful bytes of ANS */ |
|
+/* (ans[0]..ans[ans_len-1]). */ |
|
+/* Return: */ |
|
+/******************************************************/ |
|
+static void |
|
+_asn1_tag_der (unsigned char class, unsigned int tag_value, |
|
+ unsigned char ans[ASN1_MAX_TAG_SIZE], int *ans_len) |
|
+{ |
|
+ int k; |
|
+ unsigned char temp[ASN1_MAX_TAG_SIZE]; |
|
+ |
|
+ if (tag_value < 31) |
|
+ { |
|
+ /* short form */ |
|
+ ans[0] = (class & 0xE0) + ((unsigned char) (tag_value & 0x1F)); |
|
+ *ans_len = 1; |
|
+ } |
|
+ else |
|
+ { |
|
+ /* Long form */ |
|
+ ans[0] = (class & 0xE0) + 31; |
|
+ k = 0; |
|
+ while (tag_value != 0) |
|
+ { |
|
+ temp[k++] = tag_value & 0x7F; |
|
+ tag_value >>= 7; |
|
+ |
|
+ if (k > ASN1_MAX_TAG_SIZE - 1) |
|
+ break; /* will not encode larger tags */ |
|
+ } |
|
+ *ans_len = k + 1; |
|
+ while (k--) |
|
+ ans[*ans_len - 1 - k] = temp[k] + 128; |
|
+ ans[*ans_len - 1] -= 128; |
|
+ } |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_octet_der: |
|
+ * @str: the input data. |
|
+ * @str_len: STR length (str[0]..str[*str_len-1]). |
|
+ * @der: encoded string returned. |
|
+ * @der_len: number of meaningful bytes of DER (der[0]..der[der_len-1]). |
|
+ * |
|
+ * Creates a length-value DER encoding for the input data. |
|
+ * The DER encoding of the input data will be placed in the @der variable. |
|
+ * |
|
+ * Note that the OCTET STRING tag is not included in the output. |
|
+ * |
|
+ * This function does not return any value because it is expected |
|
+ * that @der_len will contain enough bytes to store the string |
|
+ * plus the DER encoding. The DER encoding size can be obtained using |
|
+ * asn1_length_der(). |
|
+ **/ |
|
+void |
|
+asn1_octet_der (const unsigned char *str, int str_len, |
|
+ unsigned char *der, int *der_len) |
|
+{ |
|
+ int len_len; |
|
+ |
|
+ if (der == NULL || str_len < 0) |
|
+ return; |
|
+ |
|
+ asn1_length_der (str_len, der, &len_len); |
|
+ memcpy (der + len_len, str, str_len); |
|
+ *der_len = str_len + len_len; |
|
+} |
|
+ |
|
+ |
|
+/** |
|
+ * asn1_encode_simple_der: |
|
+ * @etype: The type of the string to be encoded (ASN1_ETYPE_) |
|
+ * @str: the string data. |
|
+ * @str_len: the string length |
|
+ * @tl: the encoded tag and length |
|
+ * @tl_len: the bytes of the @tl field |
|
+ * |
|
+ * Creates the DER encoding for various simple ASN.1 types like strings etc. |
|
+ * It stores the tag and length in @tl, which should have space for at least |
|
+ * %ASN1_MAX_TL_SIZE bytes. Initially @tl_len should contain the size of @tl. |
|
+ * |
|
+ * The complete DER encoding should consist of the value in @tl appended |
|
+ * with the provided @str. |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if successful or an error value. |
|
+ **/ |
|
+int |
|
+asn1_encode_simple_der (unsigned int etype, const unsigned char *str, |
|
+ unsigned int str_len, unsigned char *tl, |
|
+ unsigned int *tl_len) |
|
+{ |
|
+ int tag_len, len_len; |
|
+ unsigned tlen; |
|
+ unsigned char der_tag[ASN1_MAX_TAG_SIZE]; |
|
+ unsigned char der_length[ASN1_MAX_LENGTH_SIZE]; |
|
+ unsigned char *p; |
|
+ |
|
+ if (str == NULL) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ |
|
+ if (ETYPE_OK (etype) == 0) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ |
|
+ /* doesn't handle constructed classes */ |
|
+ if (ETYPE_CLASS (etype) != ASN1_CLASS_UNIVERSAL) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ |
|
+ _asn1_tag_der (ETYPE_CLASS (etype), ETYPE_TAG (etype), der_tag, &tag_len); |
|
+ |
|
+ asn1_length_der (str_len, der_length, &len_len); |
|
+ |
|
+ if (tag_len <= 0 || len_len <= 0) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ |
|
+ tlen = tag_len + len_len; |
|
+ |
|
+ if (*tl_len < tlen) |
|
+ return ASN1_MEM_ERROR; |
|
+ |
|
+ p = tl; |
|
+ memcpy (p, der_tag, tag_len); |
|
+ p += tag_len; |
|
+ memcpy (p, der_length, len_len); |
|
+ |
|
+ *tl_len = tlen; |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+/******************************************************/ |
|
+/* Function : _asn1_time_der */ |
|
+/* Description: creates the DER coding for a TIME */ |
|
+/* type (length included). */ |
|
+/* Parameters: */ |
|
+/* str: TIME null-terminated string. */ |
|
+/* der: string returned. */ |
|
+/* der_len: number of meaningful bytes of DER */ |
|
+/* (der[0]..der[ans_len-1]). Initially it */ |
|
+/* if must store the lenght of DER. */ |
|
+/* Return: */ |
|
+/* ASN1_MEM_ERROR when DER isn't big enough */ |
|
+/* ASN1_SUCCESS otherwise */ |
|
+/******************************************************/ |
|
+static int |
|
+_asn1_time_der (unsigned char *str, int str_len, unsigned char *der, |
|
+ int *der_len) |
|
+{ |
|
+ int len_len; |
|
+ int max_len; |
|
+ |
|
+ if (der == NULL) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ |
|
+ max_len = *der_len; |
|
+ |
|
+ asn1_length_der (str_len, (max_len > 0) ? der : NULL, &len_len); |
|
+ |
|
+ if ((len_len + str_len) <= max_len) |
|
+ memcpy (der + len_len, str, str_len); |
|
+ *der_len = len_len + str_len; |
|
+ |
|
+ if ((*der_len) > max_len) |
|
+ return ASN1_MEM_ERROR; |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+ |
|
+/* |
|
+void |
|
+_asn1_get_utctime_der(unsigned char *der,int *der_len,unsigned char *str) |
|
+{ |
|
+ int len_len,str_len; |
|
+ char temp[20]; |
|
+ |
|
+ if(str==NULL) return; |
|
+ str_len=asn1_get_length_der(der,*der_len,&len_len); |
|
+ if (str_len<0) return; |
|
+ memcpy(temp,der+len_len,str_len); |
|
+ *der_len=str_len+len_len; |
|
+ switch(str_len) |
|
+ { |
|
+ case 11: |
|
+ temp[10]=0; |
|
+ strcat(temp,"00+0000"); |
|
+ break; |
|
+ case 13: |
|
+ temp[12]=0; |
|
+ strcat(temp,"+0000"); |
|
+ break; |
|
+ case 15: |
|
+ temp[15]=0; |
|
+ memmove(temp+12,temp+10,6); |
|
+ temp[10]=temp[11]='0'; |
|
+ break; |
|
+ case 17: |
|
+ temp[17]=0; |
|
+ break; |
|
+ default: |
|
+ return; |
|
+ } |
|
+ strcpy(str,temp); |
|
+} |
|
+*/ |
|
+ |
|
+static |
|
+void encode_val(uint64_t val, unsigned char *der, int max_len, int *der_len) |
|
+{ |
|
+ int first, k; |
|
+ unsigned char bit7; |
|
+ |
|
+ first = 0; |
|
+ for (k = sizeof(val); k >= 0; k--) |
|
+ { |
|
+ bit7 = (val >> (k * 7)) & 0x7F; |
|
+ if (bit7 || first || !k) |
|
+ { |
|
+ if (k) |
|
+ bit7 |= 0x80; |
|
+ if (max_len > (*der_len)) |
|
+ der[*der_len] = bit7; |
|
+ (*der_len)++; |
|
+ first = 1; |
|
+ } |
|
+ } |
|
+} |
|
+ |
|
+/******************************************************/ |
|
+/* Function : _asn1_object_id_der */ |
|
+/* Description: creates the DER coding for an */ |
|
+/* OBJECT IDENTIFIER type (length included). */ |
|
+/* Parameters: */ |
|
+/* str: OBJECT IDENTIFIER null-terminated string. */ |
|
+/* der: string returned. */ |
|
+/* der_len: number of meaningful bytes of DER */ |
|
+/* (der[0]..der[ans_len-1]). Initially it */ |
|
+/* must store the length of DER. */ |
|
+/* Return: */ |
|
+/* ASN1_MEM_ERROR when DER isn't big enough */ |
|
+/* ASN1_SUCCESS if succesful */ |
|
+/* or an error value. */ |
|
+/******************************************************/ |
|
+static int |
|
+_asn1_object_id_der (const char *str, unsigned char *der, int *der_len) |
|
+{ |
|
+ int len_len, counter, max_len; |
|
+ char *temp, *n_end, *n_start; |
|
+ uint64_t val, val1 = 0; |
|
+ int str_len = _asn1_strlen (str); |
|
+ |
|
+ max_len = *der_len; |
|
+ *der_len = 0; |
|
+ |
|
+ if (der == NULL && max_len > 0) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ |
|
+ temp = malloc (str_len + 2); |
|
+ if (temp == NULL) |
|
+ return ASN1_MEM_ALLOC_ERROR; |
|
+ |
|
+ memcpy (temp, str, str_len); |
|
+ temp[str_len] = '.'; |
|
+ temp[str_len + 1] = 0; |
|
+ |
|
+ counter = 0; |
|
+ n_start = temp; |
|
+ while ((n_end = strchr (n_start, '.'))) |
|
+ { |
|
+ *n_end = 0; |
|
+ val = _asn1_strtou64 (n_start, NULL, 10); |
|
+ counter++; |
|
+ |
|
+ if (counter == 1) |
|
+ { |
|
+ val1 = val; |
|
+ } |
|
+ else if (counter == 2) |
|
+ { |
|
+ uint64_t val0; |
|
+ |
|
+ if (val1 > 2) |
|
+ { |
|
+ free(temp); |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ } |
|
+ else if ((val1 == 0 || val1 == 1) && val > 39) |
|
+ { |
|
+ free(temp); |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ } |
|
+ |
|
+ val0 = 40 * val1 + val; |
|
+ encode_val(val0, der, max_len, der_len); |
|
+ } |
|
+ else |
|
+ { |
|
+ encode_val(val, der, max_len, der_len); |
|
+ } |
|
+ n_start = n_end + 1; |
|
+ } |
|
+ |
|
+ asn1_length_der (*der_len, NULL, &len_len); |
|
+ if (max_len >= (*der_len + len_len)) |
|
+ { |
|
+ memmove (der + len_len, der, *der_len); |
|
+ asn1_length_der (*der_len, der, &len_len); |
|
+ } |
|
+ *der_len += len_len; |
|
+ |
|
+ free (temp); |
|
+ |
|
+ if (max_len < (*der_len)) |
|
+ return ASN1_MEM_ERROR; |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_object_id_der: |
|
+ * @str: An object identifier in numeric, dot format. |
|
+ * @der: buffer to hold the returned encoding (may be %NULL). |
|
+ * @der_len: initially the size of @der; will hold the final size. |
|
+ * @flags: must be zero |
|
+ * |
|
+ * Creates the DER encoding of the provided object identifier. |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if DER encoding was OK, %ASN1_VALUE_NOT_VALID |
|
+ * if @str is not a valid OID, %ASN1_MEM_ERROR if the @der |
|
+ * vector isn't big enough and in this case @der_len will contain the |
|
+ * length needed. |
|
+ **/ |
|
+int asn1_object_id_der(const char *str, unsigned char *der, int *der_len, unsigned flags) |
|
+{ |
|
+ unsigned char tag_der[MAX_TAG_LEN]; |
|
+ int tag_len = 0, r; |
|
+ int max_len = *der_len; |
|
+ |
|
+ *der_len = 0; |
|
+ |
|
+ _asn1_tag_der (ETYPE_CLASS (ASN1_ETYPE_OBJECT_ID), ETYPE_TAG (ASN1_ETYPE_OBJECT_ID), |
|
+ tag_der, &tag_len); |
|
+ |
|
+ if (max_len > tag_len) |
|
+ { |
|
+ memcpy(der, tag_der, tag_len); |
|
+ } |
|
+ max_len -= tag_len; |
|
+ der += tag_len; |
|
+ |
|
+ r = _asn1_object_id_der (str, der, &max_len); |
|
+ if (r == ASN1_MEM_ERROR || r == ASN1_SUCCESS) |
|
+ { |
|
+ *der_len = max_len + tag_len; |
|
+ } |
|
+ |
|
+ return r; |
|
+} |
|
+ |
|
+static const unsigned char bit_mask[] = |
|
+ { 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80 }; |
|
+ |
|
+/** |
|
+ * asn1_bit_der: |
|
+ * @str: BIT string. |
|
+ * @bit_len: number of meaningful bits in STR. |
|
+ * @der: string returned. |
|
+ * @der_len: number of meaningful bytes of DER |
|
+ * (der[0]..der[ans_len-1]). |
|
+ * |
|
+ * Creates a length-value DER encoding for the input data |
|
+ * as it would have been for a BIT STRING. |
|
+ * The DER encoded data will be copied in @der. |
|
+ * |
|
+ * Note that the BIT STRING tag is not included in the output. |
|
+ * |
|
+ * This function does not return any value because it is expected |
|
+ * that @der_len will contain enough bytes to store the string |
|
+ * plus the DER encoding. The DER encoding size can be obtained using |
|
+ * asn1_length_der(). |
|
+ **/ |
|
+void |
|
+asn1_bit_der (const unsigned char *str, int bit_len, |
|
+ unsigned char *der, int *der_len) |
|
+{ |
|
+ int len_len, len_byte, len_pad; |
|
+ |
|
+ if (der == NULL) |
|
+ return; |
|
+ |
|
+ len_byte = bit_len >> 3; |
|
+ len_pad = 8 - (bit_len & 7); |
|
+ if (len_pad == 8) |
|
+ len_pad = 0; |
|
+ else |
|
+ len_byte++; |
|
+ asn1_length_der (len_byte + 1, der, &len_len); |
|
+ der[len_len] = len_pad; |
|
+ |
|
+ if (str) |
|
+ memcpy (der + len_len + 1, str, len_byte); |
|
+ der[len_len + len_byte] &= bit_mask[len_pad]; |
|
+ *der_len = len_byte + len_len + 1; |
|
+} |
|
+ |
|
+ |
|
+/******************************************************/ |
|
+/* Function : _asn1_complete_explicit_tag */ |
|
+/* Description: add the length coding to the EXPLICIT */ |
|
+/* tags. */ |
|
+/* Parameters: */ |
|
+/* node: pointer to the tree element. */ |
|
+/* der: string with the DER coding of the whole tree*/ |
|
+/* counter: number of meaningful bytes of DER */ |
|
+/* (der[0]..der[*counter-1]). */ |
|
+/* max_len: size of der vector */ |
|
+/* Return: */ |
|
+/* ASN1_MEM_ERROR if der vector isn't big enough, */ |
|
+/* otherwise ASN1_SUCCESS. */ |
|
+/******************************************************/ |
|
+static int |
|
+_asn1_complete_explicit_tag (asn1_node node, unsigned char *der, |
|
+ int *counter, int *max_len) |
|
+{ |
|
+ asn1_node p; |
|
+ int is_tag_implicit, len2, len3; |
|
+ unsigned char temp[SIZEOF_UNSIGNED_INT]; |
|
+ |
|
+ if (der == NULL && *max_len > 0) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ |
|
+ is_tag_implicit = 0; |
|
+ |
|
+ if (node->type & CONST_TAG) |
|
+ { |
|
+ p = node->down; |
|
+ if (p == NULL) |
|
+ return ASN1_DER_ERROR; |
|
+ /* When there are nested tags we must complete them reverse to |
|
+ the order they were created. This is because completing a tag |
|
+ modifies all data within it, including the incomplete tags |
|
+ which store buffer positions -- simon@josefsson.org 2002-09-06 |
|
+ */ |
|
+ while (p->right) |
|
+ p = p->right; |
|
+ while (p && p != node->down->left) |
|
+ { |
|
+ if (type_field (p->type) == ASN1_ETYPE_TAG) |
|
+ { |
|
+ if (p->type & CONST_EXPLICIT) |
|
+ { |
|
+ len2 = strtol (p->name, NULL, 10); |
|
+ _asn1_set_name (p, NULL); |
|
+ |
|
+ asn1_length_der (*counter - len2, temp, &len3); |
|
+ if (len3 <= (*max_len)) |
|
+ { |
|
+ memmove (der + len2 + len3, der + len2, |
|
+ *counter - len2); |
|
+ memcpy (der + len2, temp, len3); |
|
+ } |
|
+ *max_len -= len3; |
|
+ *counter += len3; |
|
+ is_tag_implicit = 0; |
|
+ } |
|
+ else |
|
+ { /* CONST_IMPLICIT */ |
|
+ if (!is_tag_implicit) |
|
+ { |
|
+ is_tag_implicit = 1; |
|
+ } |
|
+ } |
|
+ } |
|
+ p = p->left; |
|
+ } |
|
+ } |
|
+ |
|
+ if (*max_len < 0) |
|
+ return ASN1_MEM_ERROR; |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+const tag_and_class_st _asn1_tags[] = { |
|
+ [ASN1_ETYPE_GENERALSTRING] = |
|
+ {ASN1_TAG_GENERALSTRING, ASN1_CLASS_UNIVERSAL, "type:GENERALSTRING"}, |
|
+ [ASN1_ETYPE_NUMERIC_STRING] = |
|
+ {ASN1_TAG_NUMERIC_STRING, ASN1_CLASS_UNIVERSAL, "type:NUMERIC_STR"}, |
|
+ [ASN1_ETYPE_IA5_STRING] = |
|
+ {ASN1_TAG_IA5_STRING, ASN1_CLASS_UNIVERSAL, "type:IA5_STR"}, |
|
+ [ASN1_ETYPE_TELETEX_STRING] = |
|
+ {ASN1_TAG_TELETEX_STRING, ASN1_CLASS_UNIVERSAL, "type:TELETEX_STR"}, |
|
+ [ASN1_ETYPE_PRINTABLE_STRING] = |
|
+ {ASN1_TAG_PRINTABLE_STRING, ASN1_CLASS_UNIVERSAL, "type:PRINTABLE_STR"}, |
|
+ [ASN1_ETYPE_UNIVERSAL_STRING] = |
|
+ {ASN1_TAG_UNIVERSAL_STRING, ASN1_CLASS_UNIVERSAL, "type:UNIVERSAL_STR"}, |
|
+ [ASN1_ETYPE_BMP_STRING] = |
|
+ {ASN1_TAG_BMP_STRING, ASN1_CLASS_UNIVERSAL, "type:BMP_STR"}, |
|
+ [ASN1_ETYPE_UTF8_STRING] = |
|
+ {ASN1_TAG_UTF8_STRING, ASN1_CLASS_UNIVERSAL, "type:UTF8_STR"}, |
|
+ [ASN1_ETYPE_VISIBLE_STRING] = |
|
+ {ASN1_TAG_VISIBLE_STRING, ASN1_CLASS_UNIVERSAL, "type:VISIBLE_STR"}, |
|
+ [ASN1_ETYPE_OCTET_STRING] = |
|
+ {ASN1_TAG_OCTET_STRING, ASN1_CLASS_UNIVERSAL, "type:OCT_STR"}, |
|
+ [ASN1_ETYPE_BIT_STRING] = |
|
+ {ASN1_TAG_BIT_STRING, ASN1_CLASS_UNIVERSAL, "type:BIT_STR"}, |
|
+ [ASN1_ETYPE_OBJECT_ID] = |
|
+ {ASN1_TAG_OBJECT_ID, ASN1_CLASS_UNIVERSAL, "type:OBJ_ID"}, |
|
+ [ASN1_ETYPE_NULL] = {ASN1_TAG_NULL, ASN1_CLASS_UNIVERSAL, "type:NULL"}, |
|
+ [ASN1_ETYPE_BOOLEAN] = |
|
+ {ASN1_TAG_BOOLEAN, ASN1_CLASS_UNIVERSAL, "type:BOOLEAN"}, |
|
+ [ASN1_ETYPE_INTEGER] = |
|
+ {ASN1_TAG_INTEGER, ASN1_CLASS_UNIVERSAL, "type:INTEGER"}, |
|
+ [ASN1_ETYPE_ENUMERATED] = |
|
+ {ASN1_TAG_ENUMERATED, ASN1_CLASS_UNIVERSAL, "type:ENUMERATED"}, |
|
+ [ASN1_ETYPE_SEQUENCE] = |
|
+ {ASN1_TAG_SEQUENCE, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, |
|
+ "type:SEQUENCE"}, |
|
+ [ASN1_ETYPE_SEQUENCE_OF] = |
|
+ {ASN1_TAG_SEQUENCE, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, |
|
+ "type:SEQ_OF"}, |
|
+ [ASN1_ETYPE_SET] = |
|
+ {ASN1_TAG_SET, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, "type:SET"}, |
|
+ [ASN1_ETYPE_SET_OF] = |
|
+ {ASN1_TAG_SET, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, |
|
+ "type:SET_OF"}, |
|
+ [ASN1_ETYPE_GENERALIZED_TIME] = |
|
+ {ASN1_TAG_GENERALIZEDTime, ASN1_CLASS_UNIVERSAL, "type:GENERALIZED_TIME"}, |
|
+ [ASN1_ETYPE_UTC_TIME] = |
|
+ {ASN1_TAG_UTCTime, ASN1_CLASS_UNIVERSAL, "type:UTC_TIME"}, |
|
+}; |
|
+ |
|
+unsigned int _asn1_tags_size = sizeof (_asn1_tags) / sizeof (_asn1_tags[0]); |
|
+ |
|
+/******************************************************/ |
|
+/* Function : _asn1_insert_tag_der */ |
|
+/* Description: creates the DER coding of tags of one */ |
|
+/* NODE. */ |
|
+/* Parameters: */ |
|
+/* node: pointer to the tree element. */ |
|
+/* der: string returned */ |
|
+/* counter: number of meaningful bytes of DER */ |
|
+/* (counter[0]..der[*counter-1]). */ |
|
+/* max_len: size of der vector */ |
|
+/* Return: */ |
|
+/* ASN1_GENERIC_ERROR if the type is unknown, */ |
|
+/* ASN1_MEM_ERROR if der vector isn't big enough, */ |
|
+/* otherwise ASN1_SUCCESS. */ |
|
+/******************************************************/ |
|
+static int |
|
+_asn1_insert_tag_der (asn1_node node, unsigned char *der, int *counter, |
|
+ int *max_len) |
|
+{ |
|
+ asn1_node p; |
|
+ int tag_len, is_tag_implicit; |
|
+ unsigned char class, class_implicit = 0, temp[MAX(SIZEOF_UNSIGNED_INT * 3 + 1, LTOSTR_MAX_SIZE)]; |
|
+ unsigned long tag_implicit = 0; |
|
+ unsigned char tag_der[MAX_TAG_LEN]; |
|
+ |
|
+ is_tag_implicit = 0; |
|
+ |
|
+ if (node->type & CONST_TAG) |
|
+ { |
|
+ p = node->down; |
|
+ while (p) |
|
+ { |
|
+ if (type_field (p->type) == ASN1_ETYPE_TAG) |
|
+ { |
|
+ if (p->type & CONST_APPLICATION) |
|
+ class = ASN1_CLASS_APPLICATION; |
|
+ else if (p->type & CONST_UNIVERSAL) |
|
+ class = ASN1_CLASS_UNIVERSAL; |
|
+ else if (p->type & CONST_PRIVATE) |
|
+ class = ASN1_CLASS_PRIVATE; |
|
+ else |
|
+ class = ASN1_CLASS_CONTEXT_SPECIFIC; |
|
+ |
|
+ if (p->type & CONST_EXPLICIT) |
|
+ { |
|
+ if (is_tag_implicit) |
|
+ _asn1_tag_der (class_implicit, tag_implicit, tag_der, |
|
+ &tag_len); |
|
+ else |
|
+ _asn1_tag_der (class | ASN1_CLASS_STRUCTURED, |
|
+ _asn1_strtoul (p->value, NULL, 10), |
|
+ tag_der, &tag_len); |
|
+ |
|
+ *max_len -= tag_len; |
|
+ if (der && *max_len >= 0) |
|
+ memcpy (der + *counter, tag_der, tag_len); |
|
+ *counter += tag_len; |
|
+ |
|
+ _asn1_ltostr (*counter, (char *) temp); |
|
+ _asn1_set_name (p, (const char *) temp); |
|
+ |
|
+ is_tag_implicit = 0; |
|
+ } |
|
+ else |
|
+ { /* CONST_IMPLICIT */ |
|
+ if (!is_tag_implicit) |
|
+ { |
|
+ if ((type_field (node->type) == ASN1_ETYPE_SEQUENCE) || |
|
+ (type_field (node->type) == ASN1_ETYPE_SEQUENCE_OF) |
|
+ || (type_field (node->type) == ASN1_ETYPE_SET) |
|
+ || (type_field (node->type) == ASN1_ETYPE_SET_OF)) |
|
+ class |= ASN1_CLASS_STRUCTURED; |
|
+ class_implicit = class; |
|
+ tag_implicit = _asn1_strtoul (p->value, NULL, 10); |
|
+ is_tag_implicit = 1; |
|
+ } |
|
+ } |
|
+ } |
|
+ p = p->right; |
|
+ } |
|
+ } |
|
+ |
|
+ if (is_tag_implicit) |
|
+ { |
|
+ _asn1_tag_der (class_implicit, tag_implicit, tag_der, &tag_len); |
|
+ } |
|
+ else |
|
+ { |
|
+ unsigned type = type_field (node->type); |
|
+ switch (type) |
|
+ { |
|
+ CASE_HANDLED_ETYPES: |
|
+ _asn1_tag_der (_asn1_tags[type].class, _asn1_tags[type].tag, |
|
+ tag_der, &tag_len); |
|
+ break; |
|
+ case ASN1_ETYPE_TAG: |
|
+ case ASN1_ETYPE_CHOICE: |
|
+ case ASN1_ETYPE_ANY: |
|
+ tag_len = 0; |
|
+ break; |
|
+ default: |
|
+ return ASN1_GENERIC_ERROR; |
|
+ } |
|
+ } |
|
+ |
|
+ *max_len -= tag_len; |
|
+ if (der && *max_len >= 0) |
|
+ memcpy (der + *counter, tag_der, tag_len); |
|
+ *counter += tag_len; |
|
+ |
|
+ if (*max_len < 0) |
|
+ return ASN1_MEM_ERROR; |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+/******************************************************/ |
|
+/* Function : _asn1_ordering_set */ |
|
+/* Description: puts the elements of a SET type in */ |
|
+/* the correct order according to DER rules. */ |
|
+/* Parameters: */ |
|
+/* der: string with the DER coding. */ |
|
+/* node: pointer to the SET element. */ |
|
+/* Return: */ |
|
+/* ASN1_SUCCESS if successful */ |
|
+/* or an error value. */ |
|
+/******************************************************/ |
|
+static int |
|
+_asn1_ordering_set (unsigned char *der, int der_len, asn1_node node) |
|
+{ |
|
+ struct vet |
|
+ { |
|
+ int end; |
|
+ unsigned long value; |
|
+ struct vet *next, *prev; |
|
+ }; |
|
+ |
|
+ int counter, len, len2; |
|
+ struct vet *first, *last, *p_vet, *p2_vet; |
|
+ asn1_node p; |
|
+ unsigned char class, *temp; |
|
+ unsigned long tag, t; |
|
+ int err; |
|
+ |
|
+ counter = 0; |
|
+ |
|
+ if (type_field (node->type) != ASN1_ETYPE_SET) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ |
|
+ p = node->down; |
|
+ while (p && ((type_field (p->type) == ASN1_ETYPE_TAG) || |
|
+ (type_field (p->type) == ASN1_ETYPE_SIZE))) |
|
+ p = p->right; |
|
+ |
|
+ if ((p == NULL) || (p->right == NULL)) |
|
+ return ASN1_SUCCESS; |
|
+ |
|
+ first = last = NULL; |
|
+ while (p) |
|
+ { |
|
+ p_vet = malloc (sizeof (struct vet)); |
|
+ if (p_vet == NULL) |
|
+ { |
|
+ err = ASN1_MEM_ALLOC_ERROR; |
|
+ goto error; |
|
+ } |
|
+ |
|
+ p_vet->next = NULL; |
|
+ p_vet->prev = last; |
|
+ if (first == NULL) |
|
+ first = p_vet; |
|
+ else |
|
+ last->next = p_vet; |
|
+ last = p_vet; |
|
+ |
|
+ /* tag value calculation */ |
|
+ err = asn1_get_tag_der (der + counter, der_len - counter, &class, &len2, |
|
+ &tag); |
|
+ if (err != ASN1_SUCCESS) |
|
+ goto error; |
|
+ |
|
+ t = ((unsigned int)class) << 24; |
|
+ p_vet->value = t | tag; |
|
+ counter += len2; |
|
+ |
|
+ /* extraction and length */ |
|
+ len2 = asn1_get_length_der (der + counter, der_len - counter, &len); |
|
+ if (len2 < 0) |
|
+ { |
|
+ err = ASN1_DER_ERROR; |
|
+ goto error; |
|
+ } |
|
+ counter += len + len2; |
|
+ |
|
+ p_vet->end = counter; |
|
+ p = p->right; |
|
+ } |
|
+ |
|
+ p_vet = first; |
|
+ |
|
+ while (p_vet) |
|
+ { |
|
+ p2_vet = p_vet->next; |
|
+ counter = 0; |
|
+ while (p2_vet) |
|
+ { |
|
+ if (p_vet->value > p2_vet->value) |
|
+ { |
|
+ /* change position */ |
|
+ temp = malloc (p_vet->end - counter); |
|
+ if (temp == NULL) |
|
+ { |
|
+ err = ASN1_MEM_ALLOC_ERROR; |
|
+ goto error; |
|
+ } |
|
+ |
|
+ memcpy (temp, der + counter, p_vet->end - counter); |
|
+ memcpy (der + counter, der + p_vet->end, |
|
+ p2_vet->end - p_vet->end); |
|
+ memcpy (der + counter + p2_vet->end - p_vet->end, temp, |
|
+ p_vet->end - counter); |
|
+ free (temp); |
|
+ |
|
+ tag = p_vet->value; |
|
+ p_vet->value = p2_vet->value; |
|
+ p2_vet->value = tag; |
|
+ |
|
+ p_vet->end = counter + (p2_vet->end - p_vet->end); |
|
+ } |
|
+ counter = p_vet->end; |
|
+ |
|
+ p2_vet = p2_vet->next; |
|
+ p_vet = p_vet->next; |
|
+ } |
|
+ |
|
+ if (p_vet != first) |
|
+ p_vet->prev->next = NULL; |
|
+ else |
|
+ first = NULL; |
|
+ free (p_vet); |
|
+ p_vet = first; |
|
+ } |
|
+ return ASN1_SUCCESS; |
|
+ |
|
+error: |
|
+ while (first != NULL) |
|
+ { |
|
+ p_vet = first; |
|
+ first = first->next; |
|
+ free(p_vet); |
|
+ } |
|
+ return err; |
|
+} |
|
+ |
|
+struct vet |
|
+{ |
|
+ unsigned char *ptr; |
|
+ int size; |
|
+}; |
|
+ |
|
+static int setof_compar(const void *_e1, const void *_e2) |
|
+{ |
|
+ unsigned length; |
|
+ const struct vet *e1 = _e1, *e2 = _e2; |
|
+ int rval; |
|
+ |
|
+ /* The encodings of the component values of a set-of value shall |
|
+ * appear in ascending order, the encodings being compared |
|
+ * as octet strings with the shorter components being |
|
+ * padded at their trailing end with 0-octets. |
|
+ * The padding octets are for comparison purposes and |
|
+ * do not appear in the encodings. |
|
+ */ |
|
+ length = MIN(e1->size, e2->size); |
|
+ |
|
+ rval = memcmp(e1->ptr, e2->ptr, length); |
|
+ if (rval == 0 && e1->size != e2->size) |
|
+ { |
|
+ if (e1->size > e2->size) |
|
+ rval = 1; |
|
+ else if (e2->size > e1->size) |
|
+ rval = -1; |
|
+ } |
|
+ |
|
+ return rval; |
|
+} |
|
+ |
|
+/******************************************************/ |
|
+/* Function : _asn1_ordering_set_of */ |
|
+/* Description: puts the elements of a SET OF type in */ |
|
+/* the correct order according to DER rules. */ |
|
+/* Parameters: */ |
|
+/* der: string with the DER coding. */ |
|
+/* node: pointer to the SET OF element. */ |
|
+/* Return: */ |
|
+/* ASN1_SUCCESS if successful */ |
|
+/* or an error value. */ |
|
+/******************************************************/ |
|
+static int |
|
+_asn1_ordering_set_of (unsigned char *der, int der_len, asn1_node node) |
|
+{ |
|
+ int counter, len, len2; |
|
+ struct vet *list = NULL, *tlist; |
|
+ unsigned list_size = 0; |
|
+ struct vet *p_vet; |
|
+ asn1_node p; |
|
+ unsigned char class; |
|
+ unsigned i; |
|
+ unsigned char *out = NULL; |
|
+ int err; |
|
+ |
|
+ if (der == NULL) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ |
|
+ counter = 0; |
|
+ |
|
+ if (type_field (node->type) != ASN1_ETYPE_SET_OF) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ |
|
+ p = node->down; |
|
+ while (p && ((type_field (p->type) == ASN1_ETYPE_TAG) || |
|
+ (type_field (p->type) == ASN1_ETYPE_SIZE))) |
|
+ p = p->right; |
|
+ if (p == NULL) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ p = p->right; |
|
+ |
|
+ if ((p == NULL) || (p->right == NULL)) |
|
+ return ASN1_SUCCESS; |
|
+ |
|
+ while (p) |
|
+ { |
|
+ list_size++; |
|
+ tlist = realloc (list, list_size*sizeof(struct vet)); |
|
+ if (tlist == NULL) |
|
+ { |
|
+ err = ASN1_MEM_ALLOC_ERROR; |
|
+ goto error; |
|
+ } |
|
+ list = tlist; |
|
+ p_vet = &list[list_size-1]; |
|
+ |
|
+ p_vet->ptr = der+counter; |
|
+ p_vet->size = 0; |
|
+ |
|
+ /* extraction of tag and length */ |
|
+ if (der_len - counter > 0) |
|
+ { |
|
+ err = asn1_get_tag_der (der + counter, der_len - counter, &class, |
|
+ &len, NULL); |
|
+ if (err != ASN1_SUCCESS) |
|
+ goto error; |
|
+ counter += len; |
|
+ p_vet->size += len; |
|
+ |
|
+ len2 = asn1_get_length_der (der + counter, der_len - counter, &len); |
|
+ if (len2 < 0) |
|
+ { |
|
+ err = ASN1_DER_ERROR; |
|
+ goto error; |
|
+ } |
|
+ counter += len + len2; |
|
+ p_vet->size += len + len2; |
|
+ |
|
+ } |
|
+ else |
|
+ { |
|
+ err = ASN1_DER_ERROR; |
|
+ goto error; |
|
+ } |
|
+ p = p->right; |
|
+ } |
|
+ |
|
+ if (counter > der_len) |
|
+ { |
|
+ err = ASN1_DER_ERROR; |
|
+ goto error; |
|
+ } |
|
+ |
|
+ qsort(list, list_size, sizeof(struct vet), setof_compar); |
|
+ |
|
+ out = malloc(der_len); |
|
+ if (out == NULL) |
|
+ { |
|
+ err = ASN1_MEM_ERROR; |
|
+ goto error; |
|
+ } |
|
+ |
|
+ /* the sum of p_vet->size == der_len */ |
|
+ counter = 0; |
|
+ for (i = 0; i < list_size; i++) |
|
+ { |
|
+ p_vet = &list[i]; |
|
+ memcpy(out+counter, p_vet->ptr, p_vet->size); |
|
+ counter += p_vet->size; |
|
+ } |
|
+ memcpy(der, out, der_len); |
|
+ free(out); |
|
+ |
|
+ err = ASN1_SUCCESS; |
|
+ |
|
+error: |
|
+ free(list); |
|
+ return err; |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_der_coding: |
|
+ * @element: pointer to an ASN1 element |
|
+ * @name: the name of the structure you want to encode (it must be |
|
+ * inside *POINTER). |
|
+ * @ider: vector that will contain the DER encoding. DER must be a |
|
+ * pointer to memory cells already allocated. |
|
+ * @len: number of bytes of *@ider: @ider[0]..@ider[len-1], Initialy |
|
+ * holds the sizeof of der vector. |
|
+ * @ErrorDescription: return the error description or an empty |
|
+ * string if success. |
|
+ * |
|
+ * Creates the DER encoding for the NAME structure (inside *POINTER |
|
+ * structure). |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND |
|
+ * if @name is not a valid element, %ASN1_VALUE_NOT_FOUND if there |
|
+ * is an element without a value, %ASN1_MEM_ERROR if the @ider |
|
+ * vector isn't big enough and in this case @len will contain the |
|
+ * length needed. |
|
+ **/ |
|
+int |
|
+asn1_der_coding (asn1_node_const element, const char *name, void *ider, int *len, |
|
+ char *ErrorDescription) |
|
+{ |
|
+ asn1_node node, p, p2; |
|
+ unsigned char temp[MAX(LTOSTR_MAX_SIZE, SIZEOF_UNSIGNED_LONG_INT * 3 + 1)]; |
|
+ int counter, counter_old, len2, len3, move, max_len, max_len_old; |
|
+ int err; |
|
+ unsigned char *der = ider; |
|
+ |
|
+ if (ErrorDescription) |
|
+ ErrorDescription[0] = 0; |
|
+ |
|
+ node = asn1_find_node (element, name); |
|
+ if (node == NULL) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ /* Node is now a locally allocated variable. |
|
+ * That is because in some point we modify the |
|
+ * structure, and I don't know why! --nmav |
|
+ */ |
|
+ node = _asn1_copy_structure3 (node); |
|
+ if (node == NULL) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ max_len = *len; |
|
+ |
|
+ if (der == NULL && max_len > 0) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ |
|
+ counter = 0; |
|
+ move = DOWN; |
|
+ p = node; |
|
+ |
|
+ while (1) |
|
+ { |
|
+ |
|
+ counter_old = counter; |
|
+ max_len_old = max_len; |
|
+ if (move != UP) |
|
+ { |
|
+ p->start = counter; |
|
+ err = _asn1_insert_tag_der (p, der, &counter, &max_len); |
|
+ if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR) |
|
+ goto error; |
|
+ } |
|
+ switch (type_field (p->type)) |
|
+ { |
|
+ case ASN1_ETYPE_NULL: |
|
+ max_len--; |
|
+ if (der != NULL && max_len >= 0) |
|
+ der[counter] = 0; |
|
+ counter++; |
|
+ move = RIGHT; |
|
+ break; |
|
+ case ASN1_ETYPE_BOOLEAN: |
|
+ if ((p->type & CONST_DEFAULT) && (p->value == NULL)) |
|
+ { |
|
+ counter = counter_old; |
|
+ max_len = max_len_old; |
|
+ } |
|
+ else |
|
+ { |
|
+ if (p->value == NULL) |
|
+ { |
|
+ _asn1_error_description_value_not_found (p, |
|
+ ErrorDescription); |
|
+ err = ASN1_VALUE_NOT_FOUND; |
|
+ goto error; |
|
+ } |
|
+ max_len -= 2; |
|
+ if (der != NULL && max_len >= 0) |
|
+ { |
|
+ der[counter++] = 1; |
|
+ if (p->value[0] == 'F') |
|
+ der[counter++] = 0; |
|
+ else |
|
+ der[counter++] = 0xFF; |
|
+ } |
|
+ else |
|
+ counter += 2; |
|
+ } |
|
+ move = RIGHT; |
|
+ break; |
|
+ case ASN1_ETYPE_INTEGER: |
|
+ case ASN1_ETYPE_ENUMERATED: |
|
+ if ((p->type & CONST_DEFAULT) && (p->value == NULL)) |
|
+ { |
|
+ counter = counter_old; |
|
+ max_len = max_len_old; |
|
+ } |
|
+ else |
|
+ { |
|
+ if (p->value == NULL) |
|
+ { |
|
+ _asn1_error_description_value_not_found (p, |
|
+ ErrorDescription); |
|
+ err = ASN1_VALUE_NOT_FOUND; |
|
+ goto error; |
|
+ } |
|
+ len2 = asn1_get_length_der (p->value, p->value_len, &len3); |
|
+ if (len2 < 0) |
|
+ { |
|
+ err = ASN1_DER_ERROR; |
|
+ goto error; |
|
+ } |
|
+ max_len -= len2 + len3; |
|
+ if (der != NULL && max_len >= 0) |
|
+ memcpy (der + counter, p->value, len3 + len2); |
|
+ counter += len3 + len2; |
|
+ } |
|
+ move = RIGHT; |
|
+ break; |
|
+ case ASN1_ETYPE_OBJECT_ID: |
|
+ if ((p->type & CONST_DEFAULT) && (p->value == NULL)) |
|
+ { |
|
+ counter = counter_old; |
|
+ max_len = max_len_old; |
|
+ } |
|
+ else |
|
+ { |
|
+ if (p->value == NULL) |
|
+ { |
|
+ _asn1_error_description_value_not_found (p, |
|
+ ErrorDescription); |
|
+ err = ASN1_VALUE_NOT_FOUND; |
|
+ goto error; |
|
+ } |
|
+ len2 = max_len; |
|
+ err = _asn1_object_id_der ((char*)p->value, der + counter, &len2); |
|
+ if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR) |
|
+ goto error; |
|
+ |
|
+ max_len -= len2; |
|
+ counter += len2; |
|
+ } |
|
+ move = RIGHT; |
|
+ break; |
|
+ case ASN1_ETYPE_GENERALIZED_TIME: |
|
+ case ASN1_ETYPE_UTC_TIME: |
|
+ if (p->value == NULL) |
|
+ { |
|
+ _asn1_error_description_value_not_found (p, ErrorDescription); |
|
+ err = ASN1_VALUE_NOT_FOUND; |
|
+ goto error; |
|
+ } |
|
+ len2 = max_len; |
|
+ err = _asn1_time_der (p->value, p->value_len, der + counter, &len2); |
|
+ if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR) |
|
+ goto error; |
|
+ |
|
+ max_len -= len2; |
|
+ counter += len2; |
|
+ move = RIGHT; |
|
+ break; |
|
+ case ASN1_ETYPE_OCTET_STRING: |
|
+ case ASN1_ETYPE_GENERALSTRING: |
|
+ case ASN1_ETYPE_NUMERIC_STRING: |
|
+ case ASN1_ETYPE_IA5_STRING: |
|
+ case ASN1_ETYPE_TELETEX_STRING: |
|
+ case ASN1_ETYPE_PRINTABLE_STRING: |
|
+ case ASN1_ETYPE_UNIVERSAL_STRING: |
|
+ case ASN1_ETYPE_BMP_STRING: |
|
+ case ASN1_ETYPE_UTF8_STRING: |
|
+ case ASN1_ETYPE_VISIBLE_STRING: |
|
+ case ASN1_ETYPE_BIT_STRING: |
|
+ if (p->value == NULL) |
|
+ { |
|
+ _asn1_error_description_value_not_found (p, ErrorDescription); |
|
+ err = ASN1_VALUE_NOT_FOUND; |
|
+ goto error; |
|
+ } |
|
+ len2 = asn1_get_length_der (p->value, p->value_len, &len3); |
|
+ if (len2 < 0) |
|
+ { |
|
+ err = ASN1_DER_ERROR; |
|
+ goto error; |
|
+ } |
|
+ max_len -= len2 + len3; |
|
+ if (der != NULL && max_len >= 0) |
|
+ memcpy (der + counter, p->value, len3 + len2); |
|
+ counter += len3 + len2; |
|
+ move = RIGHT; |
|
+ break; |
|
+ case ASN1_ETYPE_SEQUENCE: |
|
+ case ASN1_ETYPE_SET: |
|
+ if (move != UP) |
|
+ { |
|
+ p->tmp_ival = counter; |
|
+ if (p->down == NULL) |
|
+ { |
|
+ move = UP; |
|
+ continue; |
|
+ } |
|
+ else |
|
+ { |
|
+ p2 = p->down; |
|
+ while (p2 && (type_field (p2->type) == ASN1_ETYPE_TAG)) |
|
+ p2 = p2->right; |
|
+ if (p2) |
|
+ { |
|
+ p = p2; |
|
+ move = RIGHT; |
|
+ continue; |
|
+ } |
|
+ move = UP; |
|
+ continue; |
|
+ } |
|
+ } |
|
+ else |
|
+ { /* move==UP */ |
|
+ len2 = p->tmp_ival; |
|
+ p->tmp_ival = 0; |
|
+ if ((type_field (p->type) == ASN1_ETYPE_SET) && (max_len >= 0)) |
|
+ { |
|
+ err = _asn1_ordering_set (der + len2, counter - len2, p); |
|
+ if (err != ASN1_SUCCESS) |
|
+ goto error; |
|
+ } |
|
+ asn1_length_der (counter - len2, temp, &len3); |
|
+ max_len -= len3; |
|
+ if (der != NULL && max_len >= 0) |
|
+ { |
|
+ memmove (der + len2 + len3, der + len2, counter - len2); |
|
+ memcpy (der + len2, temp, len3); |
|
+ } |
|
+ counter += len3; |
|
+ move = RIGHT; |
|
+ } |
|
+ break; |
|
+ case ASN1_ETYPE_SEQUENCE_OF: |
|
+ case ASN1_ETYPE_SET_OF: |
|
+ if (move != UP) |
|
+ { |
|
+ p->tmp_ival = counter; |
|
+ p = p->down; |
|
+ while ((type_field (p->type) == ASN1_ETYPE_TAG) |
|
+ || (type_field (p->type) == ASN1_ETYPE_SIZE)) |
|
+ p = p->right; |
|
+ if (p->right) |
|
+ { |
|
+ p = p->right; |
|
+ move = RIGHT; |
|
+ continue; |
|
+ } |
|
+ else |
|
+ p = _asn1_find_up (p); |
|
+ move = UP; |
|
+ } |
|
+ if (move == UP) |
|
+ { |
|
+ len2 = p->tmp_ival; |
|
+ p->tmp_ival = 0; |
|
+ if ((type_field (p->type) == ASN1_ETYPE_SET_OF) |
|
+ && (counter - len2 > 0) && (max_len >= 0)) |
|
+ { |
|
+ err = _asn1_ordering_set_of (der + len2, counter - len2, p); |
|
+ if (err != ASN1_SUCCESS) |
|
+ goto error; |
|
+ } |
|
+ asn1_length_der (counter - len2, temp, &len3); |
|
+ max_len -= len3; |
|
+ if (der != NULL && max_len >= 0) |
|
+ { |
|
+ memmove (der + len2 + len3, der + len2, counter - len2); |
|
+ memcpy (der + len2, temp, len3); |
|
+ } |
|
+ counter += len3; |
|
+ move = RIGHT; |
|
+ } |
|
+ break; |
|
+ case ASN1_ETYPE_ANY: |
|
+ if (p->value == NULL) |
|
+ { |
|
+ _asn1_error_description_value_not_found (p, ErrorDescription); |
|
+ err = ASN1_VALUE_NOT_FOUND; |
|
+ goto error; |
|
+ } |
|
+ len2 = asn1_get_length_der (p->value, p->value_len, &len3); |
|
+ if (len2 < 0) |
|
+ { |
|
+ err = ASN1_DER_ERROR; |
|
+ goto error; |
|
+ } |
|
+ max_len -= len2; |
|
+ if (der != NULL && max_len >= 0) |
|
+ memcpy (der + counter, p->value + len3, len2); |
|
+ counter += len2; |
|
+ move = RIGHT; |
|
+ break; |
|
+ default: |
|
+ move = (move == UP) ? RIGHT : DOWN; |
|
+ break; |
|
+ } |
|
+ |
|
+ if ((move != DOWN) && (counter != counter_old)) |
|
+ { |
|
+ p->end = counter - 1; |
|
+ err = _asn1_complete_explicit_tag (p, der, &counter, &max_len); |
|
+ if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR) |
|
+ goto error; |
|
+ } |
|
+ |
|
+ if (p == node && move != DOWN) |
|
+ break; |
|
+ |
|
+ if (move == DOWN) |
|
+ { |
|
+ if (p->down) |
|
+ p = p->down; |
|
+ else |
|
+ move = RIGHT; |
|
+ } |
|
+ if (move == RIGHT) |
|
+ { |
|
+ if (p->right) |
|
+ p = p->right; |
|
+ else |
|
+ move = UP; |
|
+ } |
|
+ if (move == UP) |
|
+ p = _asn1_find_up (p); |
|
+ } |
|
+ |
|
+ *len = counter; |
|
+ |
|
+ if (max_len < 0) |
|
+ { |
|
+ err = ASN1_MEM_ERROR; |
|
+ goto error; |
|
+ } |
|
+ |
|
+ err = ASN1_SUCCESS; |
|
+ |
|
+error: |
|
+ asn1_delete_structure (&node); |
|
+ return err; |
|
+} |
|
diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c |
|
new file mode 100644 |
|
index 00000000000..ff04eb778cb |
|
--- /dev/null |
|
+++ b/grub-core/lib/libtasn1/lib/decoding.c |
|
@@ -0,0 +1,2478 @@ |
|
+/* |
|
+ * Copyright (C) 2002-2016 Free Software Foundation, Inc. |
|
+ * |
|
+ * This file is part of LIBTASN1. |
|
+ * |
|
+ * The LIBTASN1 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 Street, Fifth Floor, Boston, MA |
|
+ * 02110-1301, USA |
|
+ */ |
|
+ |
|
+ |
|
+/*****************************************************/ |
|
+/* File: decoding.c */ |
|
+/* Description: Functions to manage DER decoding */ |
|
+/*****************************************************/ |
|
+ |
|
+#include <int.h> |
|
+#include <parser_aux.h> |
|
+#include <gstr.h> |
|
+#include <structure.h> |
|
+#include <element.h> |
|
+#include <limits.h> |
|
+#include <intprops.h> |
|
+#include <c-ctype.h> |
|
+ |
|
+#ifdef DEBUG |
|
+# define warn() fprintf(stderr, "%s: %d\n", __func__, __LINE__) |
|
+#else |
|
+# define warn() |
|
+#endif |
|
+ |
|
+#define IS_ERR(len, flags) (len < -1 || ((flags & ASN1_DECODE_FLAG_STRICT_DER) && len < 0)) |
|
+ |
|
+#define HAVE_TWO(x) (x>=2?1:0) |
|
+ |
|
+/* Decoding flags (dflags) used in several decoding functions. |
|
+ * DECODE_FLAG_HAVE_TAG: The provided buffer includes a tag |
|
+ * DECODE_FLAG_CONSTRUCTED: The provided buffer is of indefinite encoding (useful |
|
+ * when no tags are present). |
|
+ * DECODE_FLAG_LEVEL1: Internal flag to indicate a level of recursion for BER strings. |
|
+ * DECODE_FLAG_LEVEL2: Internal flag to indicate two levels of recursion for BER strings. |
|
+ * DECODE_FLAG_LEVEL3: Internal flag to indicate three levels of recursion for BER strings. |
|
+ * This is the maximum levels of recursion possible to prevent stack |
|
+ * exhaustion. |
|
+ */ |
|
+ |
|
+#define DECODE_FLAG_HAVE_TAG 1 |
|
+#define DECODE_FLAG_CONSTRUCTED (1<<1) |
|
+#define DECODE_FLAG_LEVEL1 (1<<2) |
|
+#define DECODE_FLAG_LEVEL2 (1<<3) |
|
+#define DECODE_FLAG_LEVEL3 (1<<4) |
|
+ |
|
+#define DECR_LEN(l, s) do { \ |
|
+ l -= s; \ |
|
+ if (l < 0) { \ |
|
+ warn(); \ |
|
+ result = ASN1_DER_ERROR; \ |
|
+ goto cleanup; \ |
|
+ } \ |
|
+ } while (0) |
|
+ |
|
+static int |
|
+_asn1_get_indefinite_length_string (const unsigned char *der, int der_len, int *len); |
|
+ |
|
+static int |
|
+_asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, |
|
+ unsigned int _der_len, unsigned char **str, |
|
+ unsigned int *str_len, unsigned int *ber_len, |
|
+ unsigned dflags); |
|
+ |
|
+static int |
|
+_asn1_decode_simple_der (unsigned int etype, const unsigned char *der, |
|
+ unsigned int _der_len, const unsigned char **str, |
|
+ unsigned int *str_len, unsigned dflags); |
|
+ |
|
+static void |
|
+_asn1_error_description_tag_error (asn1_node node, char *ErrorDescription) |
|
+{ |
|
+ |
|
+ Estrcpy (ErrorDescription, ":: tag error near element '"); |
|
+ _asn1_hierarchical_name (node, ErrorDescription + strlen (ErrorDescription), |
|
+ ASN1_MAX_ERROR_DESCRIPTION_SIZE - 40); |
|
+ Estrcat (ErrorDescription, "'"); |
|
+ |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_get_length_der: |
|
+ * @der: DER data to decode. |
|
+ * @der_len: Length of DER data to decode. |
|
+ * @len: Output variable containing the length of the DER length field. |
|
+ * |
|
+ * Extract a length field from DER data. |
|
+ * |
|
+ * Returns: Return the decoded length value, or -1 on indefinite |
|
+ * length, or -2 when the value was too big to fit in a int, or -4 |
|
+ * when the decoded length value plus @len would exceed @der_len. |
|
+ **/ |
|
+long |
|
+asn1_get_length_der (const unsigned char *der, int der_len, int *len) |
|
+{ |
|
+ unsigned int ans; |
|
+ int k, punt, sum; |
|
+ |
|
+ *len = 0; |
|
+ if (der_len <= 0) |
|
+ return 0; |
|
+ |
|
+ if (!(der[0] & 128)) |
|
+ { |
|
+ /* short form */ |
|
+ *len = 1; |
|
+ ans = der[0]; |
|
+ } |
|
+ else |
|
+ { |
|
+ /* Long form */ |
|
+ k = der[0] & 0x7F; |
|
+ punt = 1; |
|
+ if (k) |
|
+ { /* definite length method */ |
|
+ ans = 0; |
|
+ while (punt <= k && punt < der_len) |
|
+ { |
|
+ if (INT_MULTIPLY_OVERFLOW (ans, 256)) |
|
+ return -2; |
|
+ ans *= 256; |
|
+ |
|
+ if (INT_ADD_OVERFLOW (ans, ((unsigned) der[punt]))) |
|
+ return -2; |
|
+ ans += der[punt]; |
|
+ punt++; |
|
+ } |
|
+ } |
|
+ else |
|
+ { /* indefinite length method */ |
|
+ *len = punt; |
|
+ return -1; |
|
+ } |
|
+ |
|
+ *len = punt; |
|
+ } |
|
+ |
|
+ sum = ans; |
|
+ if (ans >= INT_MAX || INT_ADD_OVERFLOW (sum, (*len))) |
|
+ return -2; |
|
+ sum += *len; |
|
+ |
|
+ if (sum > der_len) |
|
+ return -4; |
|
+ |
|
+ return ans; |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_get_tag_der: |
|
+ * @der: DER data to decode. |
|
+ * @der_len: Length of DER data to decode. |
|
+ * @cls: Output variable containing decoded class. |
|
+ * @len: Output variable containing the length of the DER TAG data. |
|
+ * @tag: Output variable containing the decoded tag (may be %NULL). |
|
+ * |
|
+ * Decode the class and TAG from DER code. |
|
+ * |
|
+ * Returns: Returns %ASN1_SUCCESS on success, or an error. |
|
+ **/ |
|
+int |
|
+asn1_get_tag_der (const unsigned char *der, int der_len, |
|
+ unsigned char *cls, int *len, unsigned long *tag) |
|
+{ |
|
+ unsigned int ris; |
|
+ int punt; |
|
+ |
|
+ if (der == NULL || der_len < 2 || len == NULL) |
|
+ return ASN1_DER_ERROR; |
|
+ |
|
+ *cls = der[0] & 0xE0; |
|
+ if ((der[0] & 0x1F) != 0x1F) |
|
+ { |
|
+ /* short form */ |
|
+ *len = 1; |
|
+ ris = der[0] & 0x1F; |
|
+ } |
|
+ else |
|
+ { |
|
+ /* Long form */ |
|
+ punt = 1; |
|
+ ris = 0; |
|
+ while (punt < der_len && der[punt] & 128) |
|
+ { |
|
+ |
|
+ if (INT_MULTIPLY_OVERFLOW (ris, 128)) |
|
+ return ASN1_DER_ERROR; |
|
+ ris *= 128; |
|
+ |
|
+ if (INT_ADD_OVERFLOW (ris, ((unsigned) (der[punt] & 0x7F)))) |
|
+ return ASN1_DER_ERROR; |
|
+ ris += (der[punt] & 0x7F); |
|
+ punt++; |
|
+ } |
|
+ |
|
+ if (punt >= der_len) |
|
+ return ASN1_DER_ERROR; |
|
+ |
|
+ if (INT_MULTIPLY_OVERFLOW (ris, 128)) |
|
+ return ASN1_DER_ERROR; |
|
+ ris *= 128; |
|
+ |
|
+ if (INT_ADD_OVERFLOW (ris, ((unsigned) (der[punt] & 0x7F)))) |
|
+ return ASN1_DER_ERROR; |
|
+ ris += (der[punt] & 0x7F); |
|
+ punt++; |
|
+ |
|
+ *len = punt; |
|
+ } |
|
+ |
|
+ if (tag) |
|
+ *tag = ris; |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_get_length_ber: |
|
+ * @ber: BER data to decode. |
|
+ * @ber_len: Length of BER data to decode. |
|
+ * @len: Output variable containing the length of the BER length field. |
|
+ * |
|
+ * Extract a length field from BER data. The difference to |
|
+ * asn1_get_length_der() is that this function will return a length |
|
+ * even if the value has indefinite encoding. |
|
+ * |
|
+ * Returns: Return the decoded length value, or negative value when |
|
+ * the value was too big. |
|
+ * |
|
+ * Since: 2.0 |
|
+ **/ |
|
+long |
|
+asn1_get_length_ber (const unsigned char *ber, int ber_len, int *len) |
|
+{ |
|
+ int ret; |
|
+ long err; |
|
+ |
|
+ ret = asn1_get_length_der (ber, ber_len, len); |
|
+ |
|
+ if (ret == -1 && ber_len > 1) |
|
+ { /* indefinite length method */ |
|
+ err = _asn1_get_indefinite_length_string (ber + 1, ber_len-1, &ret); |
|
+ if (err != ASN1_SUCCESS) |
|
+ return -3; |
|
+ } |
|
+ |
|
+ return ret; |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_get_octet_der: |
|
+ * @der: DER data to decode containing the OCTET SEQUENCE. |
|
+ * @der_len: The length of the @der data to decode. |
|
+ * @ret_len: Output variable containing the encoded length of the DER data. |
|
+ * @str: Pre-allocated output buffer to put decoded OCTET SEQUENCE in. |
|
+ * @str_size: Length of pre-allocated output buffer. |
|
+ * @str_len: Output variable containing the length of the contents of the OCTET SEQUENCE. |
|
+ * |
|
+ * Extract an OCTET SEQUENCE from DER data. Note that this function |
|
+ * expects the DER data past the tag field, i.e., the length and |
|
+ * content octets. |
|
+ * |
|
+ * Returns: Returns %ASN1_SUCCESS on success, or an error. |
|
+ **/ |
|
+int |
|
+asn1_get_octet_der (const unsigned char *der, int der_len, |
|
+ int *ret_len, unsigned char *str, int str_size, |
|
+ int *str_len) |
|
+{ |
|
+ int len_len = 0; |
|
+ |
|
+ if (der_len <= 0) |
|
+ return ASN1_GENERIC_ERROR; |
|
+ |
|
+ *str_len = asn1_get_length_der (der, der_len, &len_len); |
|
+ |
|
+ if (*str_len < 0) |
|
+ return ASN1_DER_ERROR; |
|
+ |
|
+ *ret_len = *str_len + len_len; |
|
+ if (str_size >= *str_len) |
|
+ { |
|
+ if (*str_len > 0 && str != NULL) |
|
+ memcpy (str, der + len_len, *str_len); |
|
+ } |
|
+ else |
|
+ { |
|
+ return ASN1_MEM_ERROR; |
|
+ } |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+ |
|
+/*- |
|
+ * _asn1_get_time_der: |
|
+ * @type: %ASN1_ETYPE_GENERALIZED_TIME or %ASN1_ETYPE_UTC_TIME |
|
+ * @der: DER data to decode containing the time |
|
+ * @der_len: Length of DER data to decode. |
|
+ * @ret_len: Output variable containing the length of the DER data. |
|
+ * @str: Pre-allocated output buffer to put the textual time in. |
|
+ * @str_size: Length of pre-allocated output buffer. |
|
+ * @flags: Zero or %ASN1_DECODE_FLAG_STRICT_DER |
|
+ * |
|
+ * Performs basic checks in the DER encoded time object and returns its textual form. |
|
+ * The textual form will be in the YYYYMMDD000000Z format for GeneralizedTime |
|
+ * and YYMMDD000000Z for UTCTime. |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS on success, or an error. |
|
+ -*/ |
|
+static int |
|
+_asn1_get_time_der (unsigned type, const unsigned char *der, int der_len, int *ret_len, |
|
+ char *str, int str_size, unsigned flags) |
|
+{ |
|
+ int len_len, str_len; |
|
+ unsigned i; |
|
+ unsigned sign_count = 0; |
|
+ unsigned dot_count = 0; |
|
+ const unsigned char *p; |
|
+ |
|
+ if (der_len <= 0 || str == NULL) |
|
+ return ASN1_DER_ERROR; |
|
+ |
|
+ str_len = asn1_get_length_der (der, der_len, &len_len); |
|
+ if (str_len <= 0 || str_size < str_len) |
|
+ return ASN1_DER_ERROR; |
|
+ |
|
+ /* perform some sanity checks on the data */ |
|
+ if (str_len < 8) |
|
+ { |
|
+ warn(); |
|
+ return ASN1_TIME_ENCODING_ERROR; |
|
+ } |
|
+ |
|
+ if ((flags & ASN1_DECODE_FLAG_STRICT_DER) && !(flags & ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME)) |
|
+ { |
|
+ p = &der[len_len]; |
|
+ for (i=0;i<(unsigned)(str_len-1);i++) |
|
+ { |
|
+ if (c_isdigit(p[i]) == 0) |
|
+ { |
|
+ if (type == ASN1_ETYPE_GENERALIZED_TIME) |
|
+ { |
|
+ /* tolerate lax encodings */ |
|
+ if (p[i] == '.' && dot_count == 0) |
|
+ { |
|
+ dot_count++; |
|
+ continue; |
|
+ } |
|
+ |
|
+ /* This is not really valid DER, but there are |
|
+ * structures using that */ |
|
+ if (!(flags & ASN1_DECODE_FLAG_STRICT_DER) && |
|
+ (p[i] == '+' || p[i] == '-') && sign_count == 0) |
|
+ { |
|
+ sign_count++; |
|
+ continue; |
|
+ } |
|
+ } |
|
+ |
|
+ warn(); |
|
+ return ASN1_TIME_ENCODING_ERROR; |
|
+ } |
|
+ } |
|
+ |
|
+ if (sign_count == 0 && p[str_len-1] != 'Z') |
|
+ { |
|
+ warn(); |
|
+ return ASN1_TIME_ENCODING_ERROR; |
|
+ } |
|
+ } |
|
+ memcpy (str, der + len_len, str_len); |
|
+ str[str_len] = 0; |
|
+ *ret_len = str_len + len_len; |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_get_object_id_der: |
|
+ * @der: DER data to decode containing the OBJECT IDENTIFIER |
|
+ * @der_len: Length of DER data to decode. |
|
+ * @ret_len: Output variable containing the length of the DER data. |
|
+ * @str: Pre-allocated output buffer to put the textual object id in. |
|
+ * @str_size: Length of pre-allocated output buffer. |
|
+ * |
|
+ * Converts a DER encoded object identifier to its textual form. This |
|
+ * function expects the DER object identifier without the tag. |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS on success, or an error. |
|
+ **/ |
|
+int |
|
+asn1_get_object_id_der (const unsigned char *der, int der_len, int *ret_len, |
|
+ char *str, int str_size) |
|
+{ |
|
+ int len_len, len, k; |
|
+ int leading, parsed; |
|
+ char temp[LTOSTR_MAX_SIZE]; |
|
+ uint64_t val, val1, val0; |
|
+ |
|
+ *ret_len = 0; |
|
+ if (str && str_size > 0) |
|
+ str[0] = 0; /* no oid */ |
|
+ |
|
+ if (str == NULL || der_len <= 0) |
|
+ return ASN1_GENERIC_ERROR; |
|
+ |
|
+ len = asn1_get_length_der (der, der_len, &len_len); |
|
+ |
|
+ if (len <= 0 || len + len_len > der_len) |
|
+ return ASN1_DER_ERROR; |
|
+ |
|
+ /* leading octet can never be 0x80 */ |
|
+ if (der[len_len] == 0x80) |
|
+ return ASN1_DER_ERROR; |
|
+ |
|
+ val0 = 0; |
|
+ |
|
+ for (k = 0; k < len; k++) |
|
+ { |
|
+ if (INT_LEFT_SHIFT_OVERFLOW (val0, 7)) |
|
+ return ASN1_DER_ERROR; |
|
+ |
|
+ val0 <<= 7; |
|
+ val0 |= der[len_len + k] & 0x7F; |
|
+ if (!(der[len_len + k] & 0x80)) |
|
+ break; |
|
+ } |
|
+ parsed = ++k; |
|
+ |
|
+ /* val0 = (X*40) + Y, X={0,1,2}, Y<=39 when X={0,1} */ |
|
+ /* X = val, Y = val1 */ |
|
+ |
|
+ /* check if X == 0 */ |
|
+ val = 0; |
|
+ val1 = val0; |
|
+ if (val1 > 39) |
|
+ { |
|
+ val = 1; |
|
+ val1 = val0 - 40; |
|
+ if (val1 > 39) |
|
+ { |
|
+ val = 2; |
|
+ val1 = val0 - 80; |
|
+ } |
|
+ } |
|
+ |
|
+ _asn1_str_cpy (str, str_size, _asn1_ltostr (val, temp)); |
|
+ _asn1_str_cat (str, str_size, "."); |
|
+ _asn1_str_cat (str, str_size, _asn1_ltostr (val1, temp)); |
|
+ |
|
+ val = 0; |
|
+ leading = 1; |
|
+ for (k = parsed; k < len; k++) |
|
+ { |
|
+ /* X.690 mandates that the leading byte must never be 0x80 |
|
+ */ |
|
+ if (leading != 0 && der[len_len + k] == 0x80) |
|
+ return ASN1_DER_ERROR; |
|
+ leading = 0; |
|
+ |
|
+ /* check for wrap around */ |
|
+ if (INT_LEFT_SHIFT_OVERFLOW (val, 7)) |
|
+ return ASN1_DER_ERROR; |
|
+ |
|
+ val = val << 7; |
|
+ val |= der[len_len + k] & 0x7F; |
|
+ |
|
+ if (!(der[len_len + k] & 0x80)) |
|
+ { |
|
+ _asn1_str_cat (str, str_size, "."); |
|
+ _asn1_str_cat (str, str_size, _asn1_ltostr (val, temp)); |
|
+ val = 0; |
|
+ leading = 1; |
|
+ } |
|
+ } |
|
+ |
|
+ if (INT_ADD_OVERFLOW (len, len_len)) |
|
+ return ASN1_DER_ERROR; |
|
+ |
|
+ *ret_len = len + len_len; |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_get_bit_der: |
|
+ * @der: DER data to decode containing the BIT SEQUENCE. |
|
+ * @der_len: Length of DER data to decode. |
|
+ * @ret_len: Output variable containing the length of the DER data. |
|
+ * @str: Pre-allocated output buffer to put decoded BIT SEQUENCE in. |
|
+ * @str_size: Length of pre-allocated output buffer. |
|
+ * @bit_len: Output variable containing the size of the BIT SEQUENCE. |
|
+ * |
|
+ * Extract a BIT SEQUENCE from DER data. |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS on success, or an error. |
|
+ **/ |
|
+int |
|
+asn1_get_bit_der (const unsigned char *der, int der_len, |
|
+ int *ret_len, unsigned char *str, int str_size, |
|
+ int *bit_len) |
|
+{ |
|
+ int len_len = 0, len_byte; |
|
+ |
|
+ if (der_len <= 0) |
|
+ return ASN1_GENERIC_ERROR; |
|
+ |
|
+ len_byte = asn1_get_length_der (der, der_len, &len_len) - 1; |
|
+ if (len_byte < 0) |
|
+ return ASN1_DER_ERROR; |
|
+ |
|
+ *ret_len = len_byte + len_len + 1; |
|
+ *bit_len = len_byte * 8 - der[len_len]; |
|
+ |
|
+ if (*bit_len < 0) |
|
+ return ASN1_DER_ERROR; |
|
+ |
|
+ if (str_size >= len_byte) |
|
+ { |
|
+ if (len_byte > 0 && str) |
|
+ memcpy (str, der + len_len + 1, len_byte); |
|
+ } |
|
+ else |
|
+ { |
|
+ return ASN1_MEM_ERROR; |
|
+ } |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+/* tag_len: the total tag length (explicit+inner) |
|
+ * inner_tag_len: the inner_tag length |
|
+ */ |
|
+static int |
|
+_asn1_extract_tag_der (asn1_node node, const unsigned char *der, int der_len, |
|
+ int *tag_len, int *inner_tag_len, unsigned flags) |
|
+{ |
|
+ asn1_node p; |
|
+ int counter, len2, len3, is_tag_implicit; |
|
+ int result; |
|
+ unsigned long tag, tag_implicit = 0; |
|
+ unsigned char class, class2, class_implicit = 0; |
|
+ |
|
+ if (der_len <= 0) |
|
+ return ASN1_GENERIC_ERROR; |
|
+ |
|
+ counter = is_tag_implicit = 0; |
|
+ |
|
+ if (node->type & CONST_TAG) |
|
+ { |
|
+ p = node->down; |
|
+ while (p) |
|
+ { |
|
+ if (type_field (p->type) == ASN1_ETYPE_TAG) |
|
+ { |
|
+ if (p->type & CONST_APPLICATION) |
|
+ class2 = ASN1_CLASS_APPLICATION; |
|
+ else if (p->type & CONST_UNIVERSAL) |
|
+ class2 = ASN1_CLASS_UNIVERSAL; |
|
+ else if (p->type & CONST_PRIVATE) |
|
+ class2 = ASN1_CLASS_PRIVATE; |
|
+ else |
|
+ class2 = ASN1_CLASS_CONTEXT_SPECIFIC; |
|
+ |
|
+ if (p->type & CONST_EXPLICIT) |
|
+ { |
|
+ if (asn1_get_tag_der |
|
+ (der + counter, der_len, &class, &len2, |
|
+ &tag) != ASN1_SUCCESS) |
|
+ return ASN1_DER_ERROR; |
|
+ |
|
+ DECR_LEN(der_len, len2); |
|
+ counter += len2; |
|
+ |
|
+ if (flags & ASN1_DECODE_FLAG_STRICT_DER) |
|
+ len3 = |
|
+ asn1_get_length_der (der + counter, der_len, |
|
+ &len2); |
|
+ else |
|
+ len3 = |
|
+ asn1_get_length_ber (der + counter, der_len, |
|
+ &len2); |
|
+ if (len3 < 0) |
|
+ return ASN1_DER_ERROR; |
|
+ |
|
+ DECR_LEN(der_len, len2); |
|
+ counter += len2; |
|
+ |
|
+ if (!is_tag_implicit) |
|
+ { |
|
+ if ((class != (class2 | ASN1_CLASS_STRUCTURED)) || |
|
+ (tag != strtoul ((char *) p->value, NULL, 10))) |
|
+ return ASN1_TAG_ERROR; |
|
+ } |
|
+ else |
|
+ { /* ASN1_TAG_IMPLICIT */ |
|
+ if ((class != class_implicit) || (tag != tag_implicit)) |
|
+ return ASN1_TAG_ERROR; |
|
+ } |
|
+ is_tag_implicit = 0; |
|
+ } |
|
+ else |
|
+ { /* ASN1_TAG_IMPLICIT */ |
|
+ if (!is_tag_implicit) |
|
+ { |
|
+ if ((type_field (node->type) == ASN1_ETYPE_SEQUENCE) || |
|
+ (type_field (node->type) == ASN1_ETYPE_SEQUENCE_OF) |
|
+ || (type_field (node->type) == ASN1_ETYPE_SET) |
|
+ || (type_field (node->type) == ASN1_ETYPE_SET_OF)) |
|
+ class2 |= ASN1_CLASS_STRUCTURED; |
|
+ class_implicit = class2; |
|
+ tag_implicit = strtoul ((char *) p->value, NULL, 10); |
|
+ is_tag_implicit = 1; |
|
+ } |
|
+ } |
|
+ } |
|
+ p = p->right; |
|
+ } |
|
+ } |
|
+ |
|
+ if (is_tag_implicit) |
|
+ { |
|
+ if (asn1_get_tag_der |
|
+ (der + counter, der_len, &class, &len2, |
|
+ &tag) != ASN1_SUCCESS) |
|
+ return ASN1_DER_ERROR; |
|
+ |
|
+ DECR_LEN(der_len, len2); |
|
+ |
|
+ if ((class != class_implicit) || (tag != tag_implicit)) |
|
+ { |
|
+ if (type_field (node->type) == ASN1_ETYPE_OCTET_STRING) |
|
+ { |
|
+ class_implicit |= ASN1_CLASS_STRUCTURED; |
|
+ if ((class != class_implicit) || (tag != tag_implicit)) |
|
+ return ASN1_TAG_ERROR; |
|
+ } |
|
+ else |
|
+ return ASN1_TAG_ERROR; |
|
+ } |
|
+ } |
|
+ else |
|
+ { |
|
+ unsigned type = type_field (node->type); |
|
+ if (type == ASN1_ETYPE_TAG) |
|
+ { |
|
+ *tag_len = 0; |
|
+ if (inner_tag_len) |
|
+ *inner_tag_len = 0; |
|
+ return ASN1_SUCCESS; |
|
+ } |
|
+ |
|
+ if (asn1_get_tag_der |
|
+ (der + counter, der_len, &class, &len2, |
|
+ &tag) != ASN1_SUCCESS) |
|
+ return ASN1_DER_ERROR; |
|
+ |
|
+ DECR_LEN(der_len, len2); |
|
+ |
|
+ switch (type) |
|
+ { |
|
+ case ASN1_ETYPE_NULL: |
|
+ case ASN1_ETYPE_BOOLEAN: |
|
+ case ASN1_ETYPE_INTEGER: |
|
+ case ASN1_ETYPE_ENUMERATED: |
|
+ case ASN1_ETYPE_OBJECT_ID: |
|
+ case ASN1_ETYPE_GENERALSTRING: |
|
+ case ASN1_ETYPE_NUMERIC_STRING: |
|
+ case ASN1_ETYPE_IA5_STRING: |
|
+ case ASN1_ETYPE_TELETEX_STRING: |
|
+ case ASN1_ETYPE_PRINTABLE_STRING: |
|
+ case ASN1_ETYPE_UNIVERSAL_STRING: |
|
+ case ASN1_ETYPE_BMP_STRING: |
|
+ case ASN1_ETYPE_UTF8_STRING: |
|
+ case ASN1_ETYPE_VISIBLE_STRING: |
|
+ case ASN1_ETYPE_BIT_STRING: |
|
+ case ASN1_ETYPE_SEQUENCE: |
|
+ case ASN1_ETYPE_SEQUENCE_OF: |
|
+ case ASN1_ETYPE_SET: |
|
+ case ASN1_ETYPE_SET_OF: |
|
+ case ASN1_ETYPE_GENERALIZED_TIME: |
|
+ case ASN1_ETYPE_UTC_TIME: |
|
+ if ((class != _asn1_tags[type].class) |
|
+ || (tag != _asn1_tags[type].tag)) |
|
+ return ASN1_DER_ERROR; |
|
+ break; |
|
+ |
|
+ case ASN1_ETYPE_OCTET_STRING: |
|
+ /* OCTET STRING is handled differently to allow |
|
+ * BER encodings (structured class). */ |
|
+ if (((class != ASN1_CLASS_UNIVERSAL) |
|
+ && (class != (ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED))) |
|
+ || (tag != ASN1_TAG_OCTET_STRING)) |
|
+ return ASN1_DER_ERROR; |
|
+ break; |
|
+ case ASN1_ETYPE_ANY: |
|
+ counter -= len2; |
|
+ break; |
|
+ case ASN1_ETYPE_CHOICE: |
|
+ counter -= len2; |
|
+ break; |
|
+ default: |
|
+ return ASN1_DER_ERROR; |
|
+ break; |
|
+ } |
|
+ } |
|
+ |
|
+ counter += len2; |
|
+ *tag_len = counter; |
|
+ if (inner_tag_len) |
|
+ *inner_tag_len = len2; |
|
+ return ASN1_SUCCESS; |
|
+ |
|
+cleanup: |
|
+ return result; |
|
+} |
|
+ |
|
+static int |
|
+extract_tag_der_recursive(asn1_node node, const unsigned char *der, int der_len, |
|
+ int *ret_len, int *inner_len, unsigned flags) |
|
+{ |
|
+asn1_node p; |
|
+int ris = ASN1_DER_ERROR; |
|
+ |
|
+ if (type_field (node->type) == ASN1_ETYPE_CHOICE) |
|
+ { |
|
+ p = node->down; |
|
+ while (p) |
|
+ { |
|
+ ris = _asn1_extract_tag_der (p, der, der_len, ret_len, inner_len, flags); |
|
+ if (ris == ASN1_SUCCESS) |
|
+ break; |
|
+ p = p->right; |
|
+ } |
|
+ |
|
+ *ret_len = 0; |
|
+ return ris; |
|
+ } |
|
+ else |
|
+ return _asn1_extract_tag_der (node, der, der_len, ret_len, inner_len, flags); |
|
+} |
|
+ |
|
+static int |
|
+_asn1_delete_not_used (asn1_node node) |
|
+{ |
|
+ asn1_node p, p2; |
|
+ |
|
+ if (node == NULL) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ p = node; |
|
+ while (p) |
|
+ { |
|
+ if (p->type & CONST_NOT_USED) |
|
+ { |
|
+ p2 = NULL; |
|
+ if (p != node) |
|
+ { |
|
+ p2 = _asn1_find_left (p); |
|
+ if (!p2) |
|
+ p2 = _asn1_find_up (p); |
|
+ } |
|
+ asn1_delete_structure (&p); |
|
+ p = p2; |
|
+ } |
|
+ |
|
+ if (!p) |
|
+ break; /* reach node */ |
|
+ |
|
+ if (p->down) |
|
+ { |
|
+ p = p->down; |
|
+ } |
|
+ else |
|
+ { |
|
+ if (p == node) |
|
+ p = NULL; |
|
+ else if (p->right) |
|
+ p = p->right; |
|
+ else |
|
+ { |
|
+ while (1) |
|
+ { |
|
+ p = _asn1_find_up (p); |
|
+ if (p == node) |
|
+ { |
|
+ p = NULL; |
|
+ break; |
|
+ } |
|
+ if (p->right) |
|
+ { |
|
+ p = p->right; |
|
+ break; |
|
+ } |
|
+ } |
|
+ } |
|
+ } |
|
+ } |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+static int |
|
+_asn1_get_indefinite_length_string (const unsigned char *der, |
|
+ int der_len, int *len) |
|
+{ |
|
+ int len2, len3, counter, indefinite; |
|
+ int result; |
|
+ unsigned long tag; |
|
+ unsigned char class; |
|
+ |
|
+ counter = indefinite = 0; |
|
+ |
|
+ while (1) |
|
+ { |
|
+ if (HAVE_TWO(der_len) && (der[counter] == 0) && (der[counter + 1] == 0)) |
|
+ { |
|
+ counter += 2; |
|
+ DECR_LEN(der_len, 2); |
|
+ |
|
+ indefinite--; |
|
+ if (indefinite <= 0) |
|
+ break; |
|
+ else |
|
+ continue; |
|
+ } |
|
+ |
|
+ if (asn1_get_tag_der |
|
+ (der + counter, der_len, &class, &len2, |
|
+ &tag) != ASN1_SUCCESS) |
|
+ return ASN1_DER_ERROR; |
|
+ |
|
+ DECR_LEN(der_len, len2); |
|
+ counter += len2; |
|
+ |
|
+ len2 = asn1_get_length_der (der + counter, der_len, &len3); |
|
+ if (len2 < -1) |
|
+ return ASN1_DER_ERROR; |
|
+ |
|
+ if (len2 == -1) |
|
+ { |
|
+ indefinite++; |
|
+ counter += 1; |
|
+ DECR_LEN(der_len, 1); |
|
+ } |
|
+ else |
|
+ { |
|
+ counter += len2 + len3; |
|
+ DECR_LEN(der_len, len2+len3); |
|
+ } |
|
+ } |
|
+ |
|
+ *len = counter; |
|
+ return ASN1_SUCCESS; |
|
+ |
|
+cleanup: |
|
+ return result; |
|
+} |
|
+ |
|
+static void delete_unneeded_choice_fields(asn1_node p) |
|
+{ |
|
+ asn1_node p2; |
|
+ |
|
+ while (p->right) |
|
+ { |
|
+ p2 = p->right; |
|
+ asn1_delete_structure (&p2); |
|
+ } |
|
+} |
|
+ |
|
+ |
|
+/** |
|
+ * asn1_der_decoding2 |
|
+ * @element: pointer to an ASN1 structure. |
|
+ * @ider: vector that contains the DER encoding. |
|
+ * @max_ider_len: pointer to an integer giving the information about the |
|
+ * maximal number of bytes occupied by *@ider. The real size of the DER |
|
+ * encoding is returned through this pointer. |
|
+ * @flags: flags controlling the behaviour of the function. |
|
+ * @errorDescription: null-terminated string contains details when an |
|
+ * error occurred. |
|
+ * |
|
+ * Fill the structure *@element with values of a DER encoding string. The |
|
+ * structure must just be created with function asn1_create_element(). |
|
+ * |
|
+ * If %ASN1_DECODE_FLAG_ALLOW_PADDING flag is set then the function will ignore |
|
+ * padding after the decoded DER data. Upon a successful return the value of |
|
+ * *@max_ider_len will be set to the number of bytes decoded. |
|
+ * |
|
+ * If %ASN1_DECODE_FLAG_STRICT_DER flag is set then the function will |
|
+ * not decode any BER-encoded elements. |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND |
|
+ * if @ELEMENT is %NULL, and %ASN1_TAG_ERROR or |
|
+ * %ASN1_DER_ERROR if the der encoding doesn't match the structure |
|
+ * name (*@ELEMENT deleted). |
|
+ **/ |
|
+int |
|
+asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, |
|
+ unsigned int flags, char *errorDescription) |
|
+{ |
|
+ asn1_node node, p, p2, p3; |
|
+ char temp[128]; |
|
+ int counter, len2, len3, len4, move, ris, tlen; |
|
+ struct node_tail_cache_st tcache = {NULL, NULL}; |
|
+ unsigned char class; |
|
+ unsigned long tag; |
|
+ int tag_len; |
|
+ int indefinite, result, total_len = *max_ider_len, ider_len = *max_ider_len; |
|
+ int inner_tag_len; |
|
+ unsigned char *ptmp; |
|
+ const unsigned char *ptag; |
|
+ const unsigned char *der = ider; |
|
+ |
|
+ node = *element; |
|
+ |
|
+ if (errorDescription != NULL) |
|
+ errorDescription[0] = 0; |
|
+ |
|
+ if (node == NULL) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ if (node->type & CONST_OPTION) |
|
+ { |
|
+ result = ASN1_GENERIC_ERROR; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ counter = 0; |
|
+ move = DOWN; |
|
+ p = node; |
|
+ while (1) |
|
+ { |
|
+ tag_len = 0; |
|
+ inner_tag_len = 0; |
|
+ ris = ASN1_SUCCESS; |
|
+ if (move != UP) |
|
+ { |
|
+ if (p->type & CONST_SET) |
|
+ { |
|
+ p2 = _asn1_find_up (p); |
|
+ len2 = p2->tmp_ival; |
|
+ if (len2 == -1) |
|
+ { |
|
+ if (HAVE_TWO(ider_len) && !der[counter] && !der[counter + 1]) |
|
+ { |
|
+ p = p2; |
|
+ move = UP; |
|
+ counter += 2; |
|
+ DECR_LEN(ider_len, 2); |
|
+ continue; |
|
+ } |
|
+ } |
|
+ else if (counter == len2) |
|
+ { |
|
+ p = p2; |
|
+ move = UP; |
|
+ continue; |
|
+ } |
|
+ else if (counter > len2) |
|
+ { |
|
+ result = ASN1_DER_ERROR; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ p2 = p2->down; |
|
+ while (p2) |
|
+ { |
|
+ if ((p2->type & CONST_SET) && (p2->type & CONST_NOT_USED)) |
|
+ { |
|
+ ris = |
|
+ extract_tag_der_recursive (p2, der + counter, |
|
+ ider_len, &len2, NULL, flags); |
|
+ if (ris == ASN1_SUCCESS) |
|
+ { |
|
+ p2->type &= ~CONST_NOT_USED; |
|
+ p = p2; |
|
+ break; |
|
+ } |
|
+ } |
|
+ p2 = p2->right; |
|
+ } |
|
+ if (p2 == NULL) |
|
+ { |
|
+ result = ASN1_DER_ERROR; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ } |
|
+ |
|
+ /* the position in the DER structure this starts */ |
|
+ p->start = counter; |
|
+ p->end = total_len - 1; |
|
+ |
|
+ if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT)) |
|
+ { |
|
+ p2 = _asn1_find_up (p); |
|
+ len2 = p2->tmp_ival; |
|
+ if (counter == len2) |
|
+ { |
|
+ if (p->right) |
|
+ { |
|
+ p2 = p->right; |
|
+ move = RIGHT; |
|
+ } |
|
+ else |
|
+ move = UP; |
|
+ |
|
+ if (p->type & CONST_OPTION) |
|
+ asn1_delete_structure (&p); |
|
+ |
|
+ p = p2; |
|
+ continue; |
|
+ } |
|
+ } |
|
+ |
|
+ if (type_field (p->type) == ASN1_ETYPE_CHOICE) |
|
+ { |
|
+ while (p->down) |
|
+ { |
|
+ ris = |
|
+ extract_tag_der_recursive (p->down, der + counter, |
|
+ ider_len, &len2, NULL, flags); |
|
+ |
|
+ if (ris == ASN1_SUCCESS) |
|
+ { |
|
+ delete_unneeded_choice_fields(p->down); |
|
+ break; |
|
+ } |
|
+ else if (ris == ASN1_ERROR_TYPE_ANY) |
|
+ { |
|
+ result = ASN1_ERROR_TYPE_ANY; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ else |
|
+ { |
|
+ p2 = p->down; |
|
+ asn1_delete_structure (&p2); |
|
+ } |
|
+ } |
|
+ |
|
+ if (p->down == NULL) |
|
+ { |
|
+ if (!(p->type & CONST_OPTION)) |
|
+ { |
|
+ result = ASN1_DER_ERROR; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ } |
|
+ else if (type_field (p->type) != ASN1_ETYPE_CHOICE) |
|
+ p = p->down; |
|
+ |
|
+ p->start = counter; |
|
+ } |
|
+ |
|
+ if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT)) |
|
+ { |
|
+ p2 = _asn1_find_up (p); |
|
+ len2 = p2->tmp_ival; |
|
+ |
|
+ if ((len2 != -1) && (counter > len2)) |
|
+ ris = ASN1_TAG_ERROR; |
|
+ } |
|
+ |
|
+ if (ris == ASN1_SUCCESS) |
|
+ ris = |
|
+ extract_tag_der_recursive (p, der + counter, ider_len, |
|
+ &tag_len, &inner_tag_len, flags); |
|
+ |
|
+ if (ris != ASN1_SUCCESS) |
|
+ { |
|
+ if (p->type & CONST_OPTION) |
|
+ { |
|
+ p->type |= CONST_NOT_USED; |
|
+ move = RIGHT; |
|
+ } |
|
+ else if (p->type & CONST_DEFAULT) |
|
+ { |
|
+ _asn1_set_value (p, NULL, 0); |
|
+ move = RIGHT; |
|
+ } |
|
+ else |
|
+ { |
|
+ if (errorDescription != NULL) |
|
+ _asn1_error_description_tag_error (p, errorDescription); |
|
+ |
|
+ result = ASN1_TAG_ERROR; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ } |
|
+ else |
|
+ { |
|
+ DECR_LEN(ider_len, tag_len); |
|
+ counter += tag_len; |
|
+ } |
|
+ } |
|
+ |
|
+ if (ris == ASN1_SUCCESS) |
|
+ { |
|
+ switch (type_field (p->type)) |
|
+ { |
|
+ case ASN1_ETYPE_NULL: |
|
+ DECR_LEN(ider_len, 1); |
|
+ if (der[counter]) |
|
+ { |
|
+ result = ASN1_DER_ERROR; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ counter++; |
|
+ move = RIGHT; |
|
+ break; |
|
+ case ASN1_ETYPE_BOOLEAN: |
|
+ DECR_LEN(ider_len, 2); |
|
+ |
|
+ if (der[counter++] != 1) |
|
+ { |
|
+ result = ASN1_DER_ERROR; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ if (der[counter++] == 0) |
|
+ _asn1_set_value (p, "F", 1); |
|
+ else |
|
+ _asn1_set_value (p, "T", 1); |
|
+ move = RIGHT; |
|
+ break; |
|
+ case ASN1_ETYPE_INTEGER: |
|
+ case ASN1_ETYPE_ENUMERATED: |
|
+ len2 = |
|
+ asn1_get_length_der (der + counter, ider_len, &len3); |
|
+ if (len2 < 0) |
|
+ { |
|
+ result = ASN1_DER_ERROR; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ DECR_LEN(ider_len, len3+len2); |
|
+ |
|
+ _asn1_set_value (p, der + counter, len3 + len2); |
|
+ counter += len3 + len2; |
|
+ move = RIGHT; |
|
+ break; |
|
+ case ASN1_ETYPE_OBJECT_ID: |
|
+ result = |
|
+ asn1_get_object_id_der (der + counter, ider_len, &len2, |
|
+ temp, sizeof (temp)); |
|
+ if (result != ASN1_SUCCESS) |
|
+ { |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ DECR_LEN(ider_len, len2); |
|
+ |
|
+ tlen = strlen (temp); |
|
+ if (tlen > 0) |
|
+ _asn1_set_value (p, temp, tlen + 1); |
|
+ |
|
+ counter += len2; |
|
+ move = RIGHT; |
|
+ break; |
|
+ case ASN1_ETYPE_GENERALIZED_TIME: |
|
+ case ASN1_ETYPE_UTC_TIME: |
|
+ result = |
|
+ _asn1_get_time_der (type_field (p->type), der + counter, ider_len, &len2, temp, |
|
+ sizeof (temp) - 1, flags); |
|
+ if (result != ASN1_SUCCESS) |
|
+ { |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ DECR_LEN(ider_len, len2); |
|
+ |
|
+ tlen = strlen (temp); |
|
+ if (tlen > 0) |
|
+ _asn1_set_value (p, temp, tlen); |
|
+ |
|
+ counter += len2; |
|
+ move = RIGHT; |
|
+ break; |
|
+ case ASN1_ETYPE_OCTET_STRING: |
|
+ if (counter < inner_tag_len) |
|
+ { |
|
+ result = ASN1_DER_ERROR; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ ptag = der + counter - inner_tag_len; |
|
+ if ((flags & ASN1_DECODE_FLAG_STRICT_DER) || !(ptag[0] & ASN1_CLASS_STRUCTURED)) |
|
+ { |
|
+ if (ptag[0] & ASN1_CLASS_STRUCTURED) |
|
+ { |
|
+ result = ASN1_DER_ERROR; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ len2 = |
|
+ asn1_get_length_der (der + counter, ider_len, &len3); |
|
+ if (len2 < 0) |
|
+ { |
|
+ result = ASN1_DER_ERROR; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ DECR_LEN(ider_len, len3+len2); |
|
+ |
|
+ _asn1_set_value (p, der + counter, len3 + len2); |
|
+ counter += len3 + len2; |
|
+ } |
|
+ else |
|
+ { |
|
+ unsigned dflags = 0, vlen, ber_len; |
|
+ |
|
+ if (ptag[0] & ASN1_CLASS_STRUCTURED) |
|
+ dflags |= DECODE_FLAG_CONSTRUCTED; |
|
+ |
|
+ result = _asn1_decode_simple_ber(type_field (p->type), der+counter, ider_len, &ptmp, &vlen, &ber_len, dflags); |
|
+ if (result != ASN1_SUCCESS) |
|
+ { |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ DECR_LEN(ider_len, ber_len); |
|
+ |
|
+ _asn1_set_value_lv (p, ptmp, vlen); |
|
+ |
|
+ counter += ber_len; |
|
+ free(ptmp); |
|
+ } |
|
+ move = RIGHT; |
|
+ break; |
|
+ case ASN1_ETYPE_GENERALSTRING: |
|
+ case ASN1_ETYPE_NUMERIC_STRING: |
|
+ case ASN1_ETYPE_IA5_STRING: |
|
+ case ASN1_ETYPE_TELETEX_STRING: |
|
+ case ASN1_ETYPE_PRINTABLE_STRING: |
|
+ case ASN1_ETYPE_UNIVERSAL_STRING: |
|
+ case ASN1_ETYPE_BMP_STRING: |
|
+ case ASN1_ETYPE_UTF8_STRING: |
|
+ case ASN1_ETYPE_VISIBLE_STRING: |
|
+ case ASN1_ETYPE_BIT_STRING: |
|
+ len2 = |
|
+ asn1_get_length_der (der + counter, ider_len, &len3); |
|
+ if (len2 < 0) |
|
+ { |
|
+ result = ASN1_DER_ERROR; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ DECR_LEN(ider_len, len3+len2); |
|
+ |
|
+ _asn1_set_value (p, der + counter, len3 + len2); |
|
+ counter += len3 + len2; |
|
+ move = RIGHT; |
|
+ break; |
|
+ case ASN1_ETYPE_SEQUENCE: |
|
+ case ASN1_ETYPE_SET: |
|
+ if (move == UP) |
|
+ { |
|
+ len2 = p->tmp_ival; |
|
+ p->tmp_ival = 0; |
|
+ if (len2 == -1) |
|
+ { /* indefinite length method */ |
|
+ DECR_LEN(ider_len, 2); |
|
+ if ((der[counter]) || der[counter + 1]) |
|
+ { |
|
+ result = ASN1_DER_ERROR; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ counter += 2; |
|
+ } |
|
+ else |
|
+ { /* definite length method */ |
|
+ if (len2 != counter) |
|
+ { |
|
+ result = ASN1_DER_ERROR; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ } |
|
+ move = RIGHT; |
|
+ } |
|
+ else |
|
+ { /* move==DOWN || move==RIGHT */ |
|
+ len3 = |
|
+ asn1_get_length_der (der + counter, ider_len, &len2); |
|
+ if (IS_ERR(len3, flags)) |
|
+ { |
|
+ result = ASN1_DER_ERROR; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ DECR_LEN(ider_len, len2); |
|
+ counter += len2; |
|
+ |
|
+ if (len3 > 0) |
|
+ { |
|
+ p->tmp_ival = counter + len3; |
|
+ move = DOWN; |
|
+ } |
|
+ else if (len3 == 0) |
|
+ { |
|
+ p2 = p->down; |
|
+ while (p2) |
|
+ { |
|
+ if (type_field (p2->type) != ASN1_ETYPE_TAG) |
|
+ { |
|
+ p3 = p2->right; |
|
+ asn1_delete_structure (&p2); |
|
+ p2 = p3; |
|
+ } |
|
+ else |
|
+ p2 = p2->right; |
|
+ } |
|
+ move = RIGHT; |
|
+ } |
|
+ else |
|
+ { /* indefinite length method */ |
|
+ p->tmp_ival = -1; |
|
+ move = DOWN; |
|
+ } |
|
+ } |
|
+ break; |
|
+ case ASN1_ETYPE_SEQUENCE_OF: |
|
+ case ASN1_ETYPE_SET_OF: |
|
+ if (move == UP) |
|
+ { |
|
+ len2 = p->tmp_ival; |
|
+ if (len2 == -1) |
|
+ { /* indefinite length method */ |
|
+ if (!HAVE_TWO(ider_len) || ((der[counter]) || der[counter + 1])) |
|
+ { |
|
+ result = _asn1_append_sequence_set (p, &tcache); |
|
+ if (result != 0) |
|
+ { |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ p = tcache.tail; |
|
+ move = RIGHT; |
|
+ continue; |
|
+ } |
|
+ |
|
+ p->tmp_ival = 0; |
|
+ tcache.tail = NULL; /* finished decoding this structure */ |
|
+ tcache.head = NULL; |
|
+ DECR_LEN(ider_len, 2); |
|
+ counter += 2; |
|
+ } |
|
+ else |
|
+ { /* definite length method */ |
|
+ if (len2 > counter) |
|
+ { |
|
+ result = _asn1_append_sequence_set (p, &tcache); |
|
+ if (result != 0) |
|
+ { |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ p = tcache.tail; |
|
+ move = RIGHT; |
|
+ continue; |
|
+ } |
|
+ |
|
+ p->tmp_ival = 0; |
|
+ tcache.tail = NULL; /* finished decoding this structure */ |
|
+ tcache.head = NULL; |
|
+ |
|
+ if (len2 != counter) |
|
+ { |
|
+ result = ASN1_DER_ERROR; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ } |
|
+ } |
|
+ else |
|
+ { /* move==DOWN || move==RIGHT */ |
|
+ len3 = |
|
+ asn1_get_length_der (der + counter, ider_len, &len2); |
|
+ if (IS_ERR(len3, flags)) |
|
+ { |
|
+ result = ASN1_DER_ERROR; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ DECR_LEN(ider_len, len2); |
|
+ counter += len2; |
|
+ if (len3) |
|
+ { |
|
+ if (len3 > 0) |
|
+ { /* definite length method */ |
|
+ p->tmp_ival = counter + len3; |
|
+ } |
|
+ else |
|
+ { /* indefinite length method */ |
|
+ p->tmp_ival = -1; |
|
+ } |
|
+ |
|
+ p2 = p->down; |
|
+ if (p2 == NULL) |
|
+ { |
|
+ result = ASN1_DER_ERROR; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ while ((type_field (p2->type) == ASN1_ETYPE_TAG) |
|
+ || (type_field (p2->type) == ASN1_ETYPE_SIZE)) |
|
+ p2 = p2->right; |
|
+ if (p2->right == NULL) |
|
+ { |
|
+ result = _asn1_append_sequence_set (p, &tcache); |
|
+ if (result != 0) |
|
+ { |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ } |
|
+ p = p2; |
|
+ } |
|
+ } |
|
+ move = RIGHT; |
|
+ break; |
|
+ case ASN1_ETYPE_ANY: |
|
+ /* Check indefinite lenth method in an EXPLICIT TAG */ |
|
+ |
|
+ if (!(flags & ASN1_DECODE_FLAG_STRICT_DER) && (p->type & CONST_TAG) && |
|
+ tag_len == 2 && (der[counter - 1] == 0x80)) |
|
+ indefinite = 1; |
|
+ else |
|
+ indefinite = 0; |
|
+ |
|
+ if (asn1_get_tag_der |
|
+ (der + counter, ider_len, &class, &len2, |
|
+ &tag) != ASN1_SUCCESS) |
|
+ { |
|
+ result = ASN1_DER_ERROR; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ DECR_LEN(ider_len, len2); |
|
+ |
|
+ len4 = |
|
+ asn1_get_length_der (der + counter + len2, |
|
+ ider_len, &len3); |
|
+ if (IS_ERR(len4, flags)) |
|
+ { |
|
+ result = ASN1_DER_ERROR; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ if (len4 != -1) /* definite */ |
|
+ { |
|
+ len2 += len4; |
|
+ |
|
+ DECR_LEN(ider_len, len4+len3); |
|
+ _asn1_set_value_lv (p, der + counter, len2 + len3); |
|
+ counter += len2 + len3; |
|
+ } |
|
+ else /* == -1 */ |
|
+ { /* indefinite length */ |
|
+ ider_len += len2; /* undo DECR_LEN */ |
|
+ |
|
+ if (counter == 0) |
|
+ { |
|
+ result = ASN1_DER_ERROR; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ result = |
|
+ _asn1_get_indefinite_length_string (der + counter, ider_len, &len2); |
|
+ if (result != ASN1_SUCCESS) |
|
+ { |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ DECR_LEN(ider_len, len2); |
|
+ _asn1_set_value_lv (p, der + counter, len2); |
|
+ counter += len2; |
|
+ |
|
+ } |
|
+ |
|
+ /* Check if a couple of 0x00 are present due to an EXPLICIT TAG with |
|
+ an indefinite length method. */ |
|
+ if (indefinite) |
|
+ { |
|
+ DECR_LEN(ider_len, 2); |
|
+ if (!der[counter] && !der[counter + 1]) |
|
+ { |
|
+ counter += 2; |
|
+ } |
|
+ else |
|
+ { |
|
+ result = ASN1_DER_ERROR; |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ } |
|
+ |
|
+ move = RIGHT; |
|
+ break; |
|
+ default: |
|
+ move = (move == UP) ? RIGHT : DOWN; |
|
+ break; |
|
+ } |
|
+ } |
|
+ |
|
+ if (p) |
|
+ { |
|
+ p->end = counter - 1; |
|
+ } |
|
+ |
|
+ if (p == node && move != DOWN) |
|
+ break; |
|
+ |
|
+ if (move == DOWN) |
|
+ { |
|
+ if (p->down) |
|
+ p = p->down; |
|
+ else |
|
+ move = RIGHT; |
|
+ } |
|
+ if ((move == RIGHT) && !(p->type & CONST_SET)) |
|
+ { |
|
+ if (p->right) |
|
+ p = p->right; |
|
+ else |
|
+ move = UP; |
|
+ } |
|
+ if (move == UP) |
|
+ p = _asn1_find_up (p); |
|
+ } |
|
+ |
|
+ _asn1_delete_not_used (*element); |
|
+ |
|
+ if ((ider_len < 0) || |
|
+ (!(flags & ASN1_DECODE_FLAG_ALLOW_PADDING) && (ider_len != 0))) |
|
+ { |
|
+ warn(); |
|
+ result = ASN1_DER_ERROR; |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ *max_ider_len = total_len - ider_len; |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+ |
|
+cleanup: |
|
+ asn1_delete_structure (element); |
|
+ return result; |
|
+} |
|
+ |
|
+ |
|
+/** |
|
+ * asn1_der_decoding: |
|
+ * @element: pointer to an ASN1 structure. |
|
+ * @ider: vector that contains the DER encoding. |
|
+ * @ider_len: number of bytes of *@ider: @ider[0]..@ider[len-1]. |
|
+ * @errorDescription: null-terminated string contains details when an |
|
+ * error occurred. |
|
+ * |
|
+ * Fill the structure *@element with values of a DER encoding |
|
+ * string. The structure must just be created with function |
|
+ * asn1_create_element(). |
|
+ * |
|
+ * Note that the *@element variable is provided as a pointer for |
|
+ * historical reasons. |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND |
|
+ * if @ELEMENT is %NULL, and %ASN1_TAG_ERROR or |
|
+ * %ASN1_DER_ERROR if the der encoding doesn't match the structure |
|
+ * name (*@ELEMENT deleted). |
|
+ **/ |
|
+int |
|
+asn1_der_decoding (asn1_node * element, const void *ider, int ider_len, |
|
+ char *errorDescription) |
|
+{ |
|
+ return asn1_der_decoding2 (element, ider, &ider_len, 0, errorDescription); |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_der_decoding_element: |
|
+ * @structure: pointer to an ASN1 structure |
|
+ * @elementName: name of the element to fill |
|
+ * @ider: vector that contains the DER encoding of the whole structure. |
|
+ * @len: number of bytes of *der: der[0]..der[len-1] |
|
+ * @errorDescription: null-terminated string contains details when an |
|
+ * error occurred. |
|
+ * |
|
+ * Fill the element named @ELEMENTNAME with values of a DER encoding |
|
+ * string. The structure must just be created with function |
|
+ * asn1_create_element(). The DER vector must contain the encoding |
|
+ * string of the whole @STRUCTURE. If an error occurs during the |
|
+ * decoding procedure, the *@STRUCTURE is deleted and set equal to |
|
+ * %NULL. |
|
+ * |
|
+ * This function is deprecated and may just be an alias to asn1_der_decoding |
|
+ * in future versions. Use asn1_der_decoding() instead. |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND |
|
+ * if ELEMENT is %NULL or @elementName == NULL, and |
|
+ * %ASN1_TAG_ERROR or %ASN1_DER_ERROR if the der encoding doesn't |
|
+ * match the structure @structure (*ELEMENT deleted). |
|
+ **/ |
|
+int |
|
+asn1_der_decoding_element (asn1_node * structure, const char *elementName, |
|
+ const void *ider, int len, char *errorDescription) |
|
+{ |
|
+ return asn1_der_decoding(structure, ider, len, errorDescription); |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_der_decoding_startEnd: |
|
+ * @element: pointer to an ASN1 element |
|
+ * @ider: vector that contains the DER encoding. |
|
+ * @ider_len: number of bytes of *@ider: @ider[0]..@ider[len-1] |
|
+ * @name_element: an element of NAME structure. |
|
+ * @start: the position of the first byte of NAME_ELEMENT decoding |
|
+ * (@ider[*start]) |
|
+ * @end: the position of the last byte of NAME_ELEMENT decoding |
|
+ * (@ider[*end]) |
|
+ * |
|
+ * Find the start and end point of an element in a DER encoding |
|
+ * string. I mean that if you have a der encoding and you have already |
|
+ * used the function asn1_der_decoding() to fill a structure, it may |
|
+ * happen that you want to find the piece of string concerning an |
|
+ * element of the structure. |
|
+ * |
|
+ * One example is the sequence "tbsCertificate" inside an X509 |
|
+ * certificate. |
|
+ * |
|
+ * Note that since libtasn1 3.7 the @ider and @ider_len parameters |
|
+ * can be omitted, if the element is already decoded using asn1_der_decoding(). |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND |
|
+ * if ELEMENT is %asn1_node EMPTY or @name_element is not a valid |
|
+ * element, %ASN1_TAG_ERROR or %ASN1_DER_ERROR if the der encoding |
|
+ * doesn't match the structure ELEMENT. |
|
+ **/ |
|
+int |
|
+asn1_der_decoding_startEnd (asn1_node element, const void *ider, int ider_len, |
|
+ const char *name_element, int *start, int *end) |
|
+{ |
|
+ asn1_node node, node_to_find; |
|
+ int result = ASN1_DER_ERROR; |
|
+ |
|
+ node = element; |
|
+ |
|
+ if (node == NULL) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ node_to_find = asn1_find_node (node, name_element); |
|
+ |
|
+ if (node_to_find == NULL) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ *start = node_to_find->start; |
|
+ *end = node_to_find->end; |
|
+ |
|
+ if (*start == 0 && *end == 0) |
|
+ { |
|
+ if (ider == NULL || ider_len == 0) |
|
+ return ASN1_GENERIC_ERROR; |
|
+ |
|
+ /* it seems asn1_der_decoding() wasn't called before. Do it now */ |
|
+ result = asn1_der_decoding (&node, ider, ider_len, NULL); |
|
+ if (result != ASN1_SUCCESS) |
|
+ { |
|
+ warn(); |
|
+ return result; |
|
+ } |
|
+ |
|
+ node_to_find = asn1_find_node (node, name_element); |
|
+ if (node_to_find == NULL) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ *start = node_to_find->start; |
|
+ *end = node_to_find->end; |
|
+ } |
|
+ |
|
+ if (*end < *start) |
|
+ return ASN1_GENERIC_ERROR; |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_expand_any_defined_by: |
|
+ * @definitions: ASN1 definitions |
|
+ * @element: pointer to an ASN1 structure |
|
+ * |
|
+ * Expands every "ANY DEFINED BY" element of a structure created from |
|
+ * a DER decoding process (asn1_der_decoding function). The element |
|
+ * ANY must be defined by an OBJECT IDENTIFIER. The type used to |
|
+ * expand the element ANY is the first one following the definition of |
|
+ * the actual value of the OBJECT IDENTIFIER. |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if Substitution OK, %ASN1_ERROR_TYPE_ANY if |
|
+ * some "ANY DEFINED BY" element couldn't be expanded due to a |
|
+ * problem in OBJECT_ID -> TYPE association, or other error codes |
|
+ * depending on DER decoding. |
|
+ **/ |
|
+int |
|
+asn1_expand_any_defined_by (asn1_node_const definitions, asn1_node * element) |
|
+{ |
|
+ char name[2 * ASN1_MAX_NAME_SIZE + 2], |
|
+ value[ASN1_MAX_NAME_SIZE]; |
|
+ int retCode = ASN1_SUCCESS, result; |
|
+ int len, len2, len3; |
|
+ asn1_node_const p2; |
|
+ asn1_node p, p3, aux = NULL; |
|
+ char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; |
|
+ const char *definitionsName; |
|
+ |
|
+ if ((definitions == NULL) || (*element == NULL)) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ definitionsName = definitions->name; |
|
+ |
|
+ p = *element; |
|
+ while (p) |
|
+ { |
|
+ |
|
+ switch (type_field (p->type)) |
|
+ { |
|
+ case ASN1_ETYPE_ANY: |
|
+ if ((p->type & CONST_DEFINED_BY) && (p->value)) |
|
+ { |
|
+ /* search the "DEF_BY" element */ |
|
+ p2 = p->down; |
|
+ while ((p2) && (type_field (p2->type) != ASN1_ETYPE_CONSTANT)) |
|
+ p2 = p2->right; |
|
+ |
|
+ if (!p2) |
|
+ { |
|
+ retCode = ASN1_ERROR_TYPE_ANY; |
|
+ break; |
|
+ } |
|
+ |
|
+ p3 = _asn1_find_up (p); |
|
+ |
|
+ if (!p3) |
|
+ { |
|
+ retCode = ASN1_ERROR_TYPE_ANY; |
|
+ break; |
|
+ } |
|
+ |
|
+ p3 = p3->down; |
|
+ while (p3) |
|
+ { |
|
+ if (!(strcmp (p3->name, p2->name))) |
|
+ break; |
|
+ p3 = p3->right; |
|
+ } |
|
+ |
|
+ if ((!p3) || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) || |
|
+ (p3->value == NULL)) |
|
+ { |
|
+ |
|
+ p3 = _asn1_find_up (p); |
|
+ p3 = _asn1_find_up (p3); |
|
+ |
|
+ if (!p3) |
|
+ { |
|
+ retCode = ASN1_ERROR_TYPE_ANY; |
|
+ break; |
|
+ } |
|
+ |
|
+ p3 = p3->down; |
|
+ |
|
+ while (p3) |
|
+ { |
|
+ if (!(strcmp (p3->name, p2->name))) |
|
+ break; |
|
+ p3 = p3->right; |
|
+ } |
|
+ |
|
+ if ((!p3) || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) |
|
+ || (p3->value == NULL)) |
|
+ { |
|
+ retCode = ASN1_ERROR_TYPE_ANY; |
|
+ break; |
|
+ } |
|
+ } |
|
+ |
|
+ /* search the OBJECT_ID into definitions */ |
|
+ p2 = definitions->down; |
|
+ while (p2) |
|
+ { |
|
+ if ((type_field (p2->type) == ASN1_ETYPE_OBJECT_ID) && |
|
+ (p2->type & CONST_ASSIGN)) |
|
+ { |
|
+ snprintf(name, sizeof(name), "%s.%s", definitionsName, p2->name); |
|
+ |
|
+ len = ASN1_MAX_NAME_SIZE; |
|
+ result = |
|
+ asn1_read_value (definitions, name, value, &len); |
|
+ |
|
+ if ((result == ASN1_SUCCESS) |
|
+ && (!_asn1_strcmp (p3->value, value))) |
|
+ { |
|
+ p2 = p2->right; /* pointer to the structure to |
|
+ use for expansion */ |
|
+ while ((p2) && (p2->type & CONST_ASSIGN)) |
|
+ p2 = p2->right; |
|
+ |
|
+ if (p2) |
|
+ { |
|
+ snprintf(name, sizeof(name), "%s.%s", definitionsName, p2->name); |
|
+ |
|
+ result = |
|
+ asn1_create_element (definitions, name, &aux); |
|
+ if (result == ASN1_SUCCESS) |
|
+ { |
|
+ _asn1_cpy_name (aux, p); |
|
+ len2 = |
|
+ asn1_get_length_der (p->value, |
|
+ p->value_len, &len3); |
|
+ if (len2 < 0) |
|
+ return ASN1_DER_ERROR; |
|
+ |
|
+ result = |
|
+ asn1_der_decoding (&aux, p->value + len3, |
|
+ len2, |
|
+ errorDescription); |
|
+ if (result == ASN1_SUCCESS) |
|
+ { |
|
+ |
|
+ _asn1_set_right (aux, p->right); |
|
+ _asn1_set_right (p, aux); |
|
+ |
|
+ result = asn1_delete_structure (&p); |
|
+ if (result == ASN1_SUCCESS) |
|
+ { |
|
+ p = aux; |
|
+ aux = NULL; |
|
+ break; |
|
+ } |
|
+ else |
|
+ { /* error with asn1_delete_structure */ |
|
+ asn1_delete_structure (&aux); |
|
+ retCode = result; |
|
+ break; |
|
+ } |
|
+ } |
|
+ else |
|
+ { /* error with asn1_der_decoding */ |
|
+ retCode = result; |
|
+ break; |
|
+ } |
|
+ } |
|
+ else |
|
+ { /* error with asn1_create_element */ |
|
+ retCode = result; |
|
+ break; |
|
+ } |
|
+ } |
|
+ else |
|
+ { /* error with the pointer to the structure to exapand */ |
|
+ retCode = ASN1_ERROR_TYPE_ANY; |
|
+ break; |
|
+ } |
|
+ } |
|
+ } |
|
+ p2 = p2->right; |
|
+ } /* end while */ |
|
+ |
|
+ if (!p2) |
|
+ { |
|
+ retCode = ASN1_ERROR_TYPE_ANY; |
|
+ break; |
|
+ } |
|
+ |
|
+ } |
|
+ break; |
|
+ default: |
|
+ break; |
|
+ } |
|
+ |
|
+ |
|
+ if (p->down) |
|
+ { |
|
+ p = p->down; |
|
+ } |
|
+ else if (p == *element) |
|
+ { |
|
+ p = NULL; |
|
+ break; |
|
+ } |
|
+ else if (p->right) |
|
+ p = p->right; |
|
+ else |
|
+ { |
|
+ while (1) |
|
+ { |
|
+ p = _asn1_find_up (p); |
|
+ if (p == *element) |
|
+ { |
|
+ p = NULL; |
|
+ break; |
|
+ } |
|
+ if (p->right) |
|
+ { |
|
+ p = p->right; |
|
+ break; |
|
+ } |
|
+ } |
|
+ } |
|
+ } |
|
+ |
|
+ return retCode; |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_expand_octet_string: |
|
+ * @definitions: ASN1 definitions |
|
+ * @element: pointer to an ASN1 structure |
|
+ * @octetName: name of the OCTECT STRING field to expand. |
|
+ * @objectName: name of the OBJECT IDENTIFIER field to use to define |
|
+ * the type for expansion. |
|
+ * |
|
+ * Expands an "OCTET STRING" element of a structure created from a DER |
|
+ * decoding process (the asn1_der_decoding() function). The type used |
|
+ * for expansion is the first one following the definition of the |
|
+ * actual value of the OBJECT IDENTIFIER indicated by OBJECTNAME. |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if substitution OK, %ASN1_ELEMENT_NOT_FOUND |
|
+ * if @objectName or @octetName are not correct, |
|
+ * %ASN1_VALUE_NOT_VALID if it wasn't possible to find the type to |
|
+ * use for expansion, or other errors depending on DER decoding. |
|
+ **/ |
|
+int |
|
+asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element, |
|
+ const char *octetName, const char *objectName) |
|
+{ |
|
+ char name[2 * ASN1_MAX_NAME_SIZE + 1], value[ASN1_MAX_NAME_SIZE]; |
|
+ int retCode = ASN1_SUCCESS, result; |
|
+ int len, len2, len3; |
|
+ asn1_node_const p2; |
|
+ asn1_node aux = NULL; |
|
+ asn1_node octetNode = NULL, objectNode = NULL; |
|
+ char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; |
|
+ |
|
+ if ((definitions == NULL) || (*element == NULL)) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ octetNode = asn1_find_node (*element, octetName); |
|
+ if (octetNode == NULL) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ if (type_field (octetNode->type) != ASN1_ETYPE_OCTET_STRING) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ if (octetNode->value == NULL) |
|
+ return ASN1_VALUE_NOT_FOUND; |
|
+ |
|
+ objectNode = asn1_find_node (*element, objectName); |
|
+ if (objectNode == NULL) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ if (type_field (objectNode->type) != ASN1_ETYPE_OBJECT_ID) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ if (objectNode->value == NULL) |
|
+ return ASN1_VALUE_NOT_FOUND; |
|
+ |
|
+ |
|
+ /* search the OBJECT_ID into definitions */ |
|
+ p2 = definitions->down; |
|
+ while (p2) |
|
+ { |
|
+ if ((type_field (p2->type) == ASN1_ETYPE_OBJECT_ID) && |
|
+ (p2->type & CONST_ASSIGN)) |
|
+ { |
|
+ strcpy (name, definitions->name); |
|
+ strcat (name, "."); |
|
+ strcat (name, p2->name); |
|
+ |
|
+ len = sizeof (value); |
|
+ result = asn1_read_value (definitions, name, value, &len); |
|
+ |
|
+ if ((result == ASN1_SUCCESS) |
|
+ && (!_asn1_strcmp (objectNode->value, value))) |
|
+ { |
|
+ |
|
+ p2 = p2->right; /* pointer to the structure to |
|
+ use for expansion */ |
|
+ while ((p2) && (p2->type & CONST_ASSIGN)) |
|
+ p2 = p2->right; |
|
+ |
|
+ if (p2) |
|
+ { |
|
+ strcpy (name, definitions->name); |
|
+ strcat (name, "."); |
|
+ strcat (name, p2->name); |
|
+ |
|
+ result = asn1_create_element (definitions, name, &aux); |
|
+ if (result == ASN1_SUCCESS) |
|
+ { |
|
+ _asn1_cpy_name (aux, octetNode); |
|
+ len2 = |
|
+ asn1_get_length_der (octetNode->value, |
|
+ octetNode->value_len, &len3); |
|
+ if (len2 < 0) |
|
+ return ASN1_DER_ERROR; |
|
+ |
|
+ result = |
|
+ asn1_der_decoding (&aux, octetNode->value + len3, |
|
+ len2, errorDescription); |
|
+ if (result == ASN1_SUCCESS) |
|
+ { |
|
+ |
|
+ _asn1_set_right (aux, octetNode->right); |
|
+ _asn1_set_right (octetNode, aux); |
|
+ |
|
+ result = asn1_delete_structure (&octetNode); |
|
+ if (result == ASN1_SUCCESS) |
|
+ { |
|
+ aux = NULL; |
|
+ break; |
|
+ } |
|
+ else |
|
+ { /* error with asn1_delete_structure */ |
|
+ asn1_delete_structure (&aux); |
|
+ retCode = result; |
|
+ break; |
|
+ } |
|
+ } |
|
+ else |
|
+ { /* error with asn1_der_decoding */ |
|
+ retCode = result; |
|
+ break; |
|
+ } |
|
+ } |
|
+ else |
|
+ { /* error with asn1_create_element */ |
|
+ retCode = result; |
|
+ break; |
|
+ } |
|
+ } |
|
+ else |
|
+ { /* error with the pointer to the structure to exapand */ |
|
+ retCode = ASN1_VALUE_NOT_VALID; |
|
+ break; |
|
+ } |
|
+ } |
|
+ } |
|
+ |
|
+ p2 = p2->right; |
|
+ |
|
+ } |
|
+ |
|
+ if (!p2) |
|
+ retCode = ASN1_VALUE_NOT_VALID; |
|
+ |
|
+ return retCode; |
|
+} |
|
+ |
|
+/*- |
|
+ * _asn1_decode_simple_der: |
|
+ * @etype: The type of the string to be encoded (ASN1_ETYPE_) |
|
+ * @der: the encoded string |
|
+ * @_der_len: the bytes of the encoded string |
|
+ * @str: a pointer to the data |
|
+ * @str_len: the length of the data |
|
+ * @dflags: DECODE_FLAG_* |
|
+ * |
|
+ * Decodes a simple DER encoded type (e.g. a string, which is not constructed). |
|
+ * The output is a pointer inside the @der. |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if successful or an error value. |
|
+ -*/ |
|
+static int |
|
+_asn1_decode_simple_der (unsigned int etype, const unsigned char *der, |
|
+ unsigned int _der_len, const unsigned char **str, |
|
+ unsigned int *str_len, unsigned dflags) |
|
+{ |
|
+ int tag_len, len_len; |
|
+ const unsigned char *p; |
|
+ int der_len = _der_len; |
|
+ unsigned char class; |
|
+ unsigned long tag; |
|
+ long ret; |
|
+ |
|
+ if (der == NULL || der_len == 0) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ |
|
+ if (ETYPE_OK (etype) == 0 || ETYPE_IS_STRING(etype) == 0) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ |
|
+ /* doesn't handle constructed classes */ |
|
+ class = ETYPE_CLASS(etype); |
|
+ if (class != ASN1_CLASS_UNIVERSAL) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ |
|
+ p = der; |
|
+ |
|
+ if (dflags & DECODE_FLAG_HAVE_TAG) |
|
+ { |
|
+ ret = asn1_get_tag_der (p, der_len, &class, &tag_len, &tag); |
|
+ if (ret != ASN1_SUCCESS) |
|
+ return ret; |
|
+ |
|
+ if (class != ETYPE_CLASS (etype) || tag != ETYPE_TAG (etype)) |
|
+ { |
|
+ warn(); |
|
+ return ASN1_DER_ERROR; |
|
+ } |
|
+ |
|
+ p += tag_len; |
|
+ der_len -= tag_len; |
|
+ if (der_len <= 0) |
|
+ return ASN1_DER_ERROR; |
|
+ } |
|
+ |
|
+ ret = asn1_get_length_der (p, der_len, &len_len); |
|
+ if (ret < 0) |
|
+ return ASN1_DER_ERROR; |
|
+ |
|
+ p += len_len; |
|
+ der_len -= len_len; |
|
+ if (der_len <= 0) |
|
+ return ASN1_DER_ERROR; |
|
+ |
|
+ *str_len = ret; |
|
+ *str = p; |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_decode_simple_der: |
|
+ * @etype: The type of the string to be encoded (ASN1_ETYPE_) |
|
+ * @der: the encoded string |
|
+ * @_der_len: the bytes of the encoded string |
|
+ * @str: a pointer to the data |
|
+ * @str_len: the length of the data |
|
+ * |
|
+ * Decodes a simple DER encoded type (e.g. a string, which is not constructed). |
|
+ * The output is a pointer inside the @der. |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if successful or an error value. |
|
+ **/ |
|
+int |
|
+asn1_decode_simple_der (unsigned int etype, const unsigned char *der, |
|
+ unsigned int _der_len, const unsigned char **str, |
|
+ unsigned int *str_len) |
|
+{ |
|
+ return _asn1_decode_simple_der(etype, der, _der_len, str, str_len, DECODE_FLAG_HAVE_TAG); |
|
+} |
|
+ |
|
+static int append(uint8_t **dst, unsigned *dst_size, const unsigned char *src, unsigned src_size) |
|
+{ |
|
+ if (src_size == 0) |
|
+ return ASN1_SUCCESS; |
|
+ |
|
+ *dst = _asn1_realloc(*dst, *dst_size+src_size); |
|
+ if (*dst == NULL) |
|
+ return ASN1_MEM_ALLOC_ERROR; |
|
+ memcpy(*dst + *dst_size, src, src_size); |
|
+ *dst_size += src_size; |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+/*- |
|
+ * _asn1_decode_simple_ber: |
|
+ * @etype: The type of the string to be encoded (ASN1_ETYPE_) |
|
+ * @der: the encoded string |
|
+ * @_der_len: the bytes of the encoded string |
|
+ * @str: a pointer to the data |
|
+ * @str_len: the length of the data |
|
+ * @ber_len: the total length occupied by BER (may be %NULL) |
|
+ * @have_tag: whether a DER tag is included |
|
+ * |
|
+ * Decodes a BER encoded type. The output is an allocated value |
|
+ * of the data. This decodes BER STRINGS only. Other types are |
|
+ * decoded as DER. |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if successful or an error value. |
|
+ -*/ |
|
+static int |
|
+_asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, |
|
+ unsigned int _der_len, unsigned char **str, |
|
+ unsigned int *str_len, unsigned int *ber_len, |
|
+ unsigned dflags) |
|
+{ |
|
+ int tag_len, len_len; |
|
+ const unsigned char *p; |
|
+ int der_len = _der_len; |
|
+ uint8_t *total = NULL; |
|
+ unsigned total_size = 0; |
|
+ unsigned char class; |
|
+ unsigned long tag; |
|
+ unsigned char *out = NULL; |
|
+ const unsigned char *cout = NULL; |
|
+ unsigned out_len; |
|
+ long result; |
|
+ |
|
+ if (ber_len) *ber_len = 0; |
|
+ |
|
+ if (der == NULL || der_len == 0) |
|
+ { |
|
+ warn(); |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ } |
|
+ |
|
+ if (ETYPE_OK (etype) == 0) |
|
+ { |
|
+ warn(); |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ } |
|
+ |
|
+ /* doesn't handle constructed + definite classes */ |
|
+ class = ETYPE_CLASS (etype); |
|
+ if (class != ASN1_CLASS_UNIVERSAL) |
|
+ { |
|
+ warn(); |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ } |
|
+ |
|
+ p = der; |
|
+ |
|
+ if (dflags & DECODE_FLAG_HAVE_TAG) |
|
+ { |
|
+ result = asn1_get_tag_der (p, der_len, &class, &tag_len, &tag); |
|
+ if (result != ASN1_SUCCESS) |
|
+ { |
|
+ warn(); |
|
+ return result; |
|
+ } |
|
+ |
|
+ if (tag != ETYPE_TAG (etype)) |
|
+ { |
|
+ warn(); |
|
+ return ASN1_DER_ERROR; |
|
+ } |
|
+ |
|
+ p += tag_len; |
|
+ |
|
+ DECR_LEN(der_len, tag_len); |
|
+ |
|
+ if (ber_len) *ber_len += tag_len; |
|
+ } |
|
+ |
|
+ /* indefinite constructed */ |
|
+ if ((((dflags & DECODE_FLAG_CONSTRUCTED) || class == ASN1_CLASS_STRUCTURED) && ETYPE_IS_STRING(etype)) && |
|
+ !(dflags & DECODE_FLAG_LEVEL3)) |
|
+ { |
|
+ if (der_len == 0) |
|
+ { |
|
+ warn(); |
|
+ result = ASN1_DER_ERROR; |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ if (der_len > 0 && p[0] == 0x80) /* indefinite */ |
|
+ { |
|
+ len_len = 1; |
|
+ DECR_LEN(der_len, len_len); |
|
+ p += len_len; |
|
+ |
|
+ if (ber_len) *ber_len += len_len; |
|
+ |
|
+ /* decode the available octet strings */ |
|
+ do |
|
+ { |
|
+ unsigned tmp_len; |
|
+ unsigned flags = DECODE_FLAG_HAVE_TAG; |
|
+ |
|
+ if (dflags & DECODE_FLAG_LEVEL1) |
|
+ flags |= DECODE_FLAG_LEVEL2; |
|
+ else if (dflags & DECODE_FLAG_LEVEL2) |
|
+ flags |= DECODE_FLAG_LEVEL3; |
|
+ else |
|
+ flags |= DECODE_FLAG_LEVEL1; |
|
+ |
|
+ result = _asn1_decode_simple_ber(etype, p, der_len, &out, &out_len, &tmp_len, |
|
+ flags); |
|
+ if (result != ASN1_SUCCESS) |
|
+ { |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ p += tmp_len; |
|
+ DECR_LEN(der_len, tmp_len); |
|
+ |
|
+ if (ber_len) *ber_len += tmp_len; |
|
+ |
|
+ DECR_LEN(der_len, 2); /* we need the EOC */ |
|
+ |
|
+ result = append(&total, &total_size, out, out_len); |
|
+ if (result != ASN1_SUCCESS) |
|
+ { |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ free(out); |
|
+ out = NULL; |
|
+ |
|
+ if (p[0] == 0 && p[1] == 0) /* EOC */ |
|
+ { |
|
+ if (ber_len) *ber_len += 2; |
|
+ break; |
|
+ } |
|
+ |
|
+ /* no EOC */ |
|
+ der_len += 2; |
|
+ |
|
+ if (der_len == 2) |
|
+ { |
|
+ warn(); |
|
+ result = ASN1_DER_ERROR; |
|
+ goto cleanup; |
|
+ } |
|
+ } |
|
+ while(1); |
|
+ } |
|
+ else /* constructed */ |
|
+ { |
|
+ long const_len; |
|
+ |
|
+ result = asn1_get_length_ber(p, der_len, &len_len); |
|
+ if (result < 0) |
|
+ { |
|
+ warn(); |
|
+ result = ASN1_DER_ERROR; |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ DECR_LEN(der_len, len_len); |
|
+ p += len_len; |
|
+ |
|
+ const_len = result; |
|
+ |
|
+ if (ber_len) *ber_len += len_len; |
|
+ |
|
+ /* decode the available octet strings */ |
|
+ while(const_len > 0) |
|
+ { |
|
+ unsigned tmp_len; |
|
+ unsigned flags = DECODE_FLAG_HAVE_TAG; |
|
+ |
|
+ if (dflags & DECODE_FLAG_LEVEL1) |
|
+ flags |= DECODE_FLAG_LEVEL2; |
|
+ else if (dflags & DECODE_FLAG_LEVEL2) |
|
+ flags |= DECODE_FLAG_LEVEL3; |
|
+ else |
|
+ flags |= DECODE_FLAG_LEVEL1; |
|
+ |
|
+ result = _asn1_decode_simple_ber(etype, p, der_len, &out, &out_len, &tmp_len, |
|
+ flags); |
|
+ if (result != ASN1_SUCCESS) |
|
+ { |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ p += tmp_len; |
|
+ DECR_LEN(der_len, tmp_len); |
|
+ DECR_LEN(const_len, tmp_len); |
|
+ |
|
+ if (ber_len) *ber_len += tmp_len; |
|
+ |
|
+ result = append(&total, &total_size, out, out_len); |
|
+ if (result != ASN1_SUCCESS) |
|
+ { |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ free(out); |
|
+ out = NULL; |
|
+ } |
|
+ } |
|
+ } |
|
+ else if (class == ETYPE_CLASS(etype)) |
|
+ { |
|
+ if (ber_len) |
|
+ { |
|
+ result = asn1_get_length_der (p, der_len, &len_len); |
|
+ if (result < 0) |
|
+ { |
|
+ warn(); |
|
+ result = ASN1_DER_ERROR; |
|
+ goto cleanup; |
|
+ } |
|
+ *ber_len += result + len_len; |
|
+ } |
|
+ |
|
+ /* non-string values are decoded as DER */ |
|
+ result = _asn1_decode_simple_der(etype, der, _der_len, &cout, &out_len, dflags); |
|
+ if (result != ASN1_SUCCESS) |
|
+ { |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ result = append(&total, &total_size, cout, out_len); |
|
+ if (result != ASN1_SUCCESS) |
|
+ { |
|
+ warn(); |
|
+ goto cleanup; |
|
+ } |
|
+ } |
|
+ else |
|
+ { |
|
+ warn(); |
|
+ result = ASN1_DER_ERROR; |
|
+ goto cleanup; |
|
+ } |
|
+ |
|
+ *str = total; |
|
+ *str_len = total_size; |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+cleanup: |
|
+ free(out); |
|
+ free(total); |
|
+ return result; |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_decode_simple_ber: |
|
+ * @etype: The type of the string to be encoded (ASN1_ETYPE_) |
|
+ * @der: the encoded string |
|
+ * @_der_len: the bytes of the encoded string |
|
+ * @str: a pointer to the data |
|
+ * @str_len: the length of the data |
|
+ * @ber_len: the total length occupied by BER (may be %NULL) |
|
+ * |
|
+ * Decodes a BER encoded type. The output is an allocated value |
|
+ * of the data. This decodes BER STRINGS only. Other types are |
|
+ * decoded as DER. |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if successful or an error value. |
|
+ **/ |
|
+int |
|
+asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, |
|
+ unsigned int _der_len, unsigned char **str, |
|
+ unsigned int *str_len, unsigned int *ber_len) |
|
+{ |
|
+ return _asn1_decode_simple_ber(etype, der, _der_len, str, str_len, ber_len, DECODE_FLAG_HAVE_TAG); |
|
+} |
|
diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c |
|
new file mode 100644 |
|
index 00000000000..997eb2725dc |
|
--- /dev/null |
|
+++ b/grub-core/lib/libtasn1/lib/element.c |
|
@@ -0,0 +1,1111 @@ |
|
+/* |
|
+ * Copyright (C) 2000-2014 Free Software Foundation, Inc. |
|
+ * |
|
+ * This file is part of LIBTASN1. |
|
+ * |
|
+ * The LIBTASN1 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 Street, Fifth Floor, Boston, MA |
|
+ * 02110-1301, USA |
|
+ */ |
|
+ |
|
+/*****************************************************/ |
|
+/* File: element.c */ |
|
+/* Description: Functions with the read and write */ |
|
+/* functions. */ |
|
+/*****************************************************/ |
|
+ |
|
+ |
|
+#include <int.h> |
|
+#include "parser_aux.h" |
|
+#include <gstr.h> |
|
+#include "structure.h" |
|
+#include "c-ctype.h" |
|
+#include "element.h" |
|
+ |
|
+void |
|
+_asn1_hierarchical_name (asn1_node_const node, char *name, int name_size) |
|
+{ |
|
+ asn1_node_const p; |
|
+ char tmp_name[64]; |
|
+ |
|
+ p = node; |
|
+ |
|
+ name[0] = 0; |
|
+ |
|
+ while (p != NULL) |
|
+ { |
|
+ if (p->name[0] != 0) |
|
+ { |
|
+ _asn1_str_cpy (tmp_name, sizeof (tmp_name), name), |
|
+ _asn1_str_cpy (name, name_size, p->name); |
|
+ _asn1_str_cat (name, name_size, "."); |
|
+ _asn1_str_cat (name, name_size, tmp_name); |
|
+ } |
|
+ p = _asn1_find_up (p); |
|
+ } |
|
+ |
|
+ if (name[0] == 0) |
|
+ _asn1_str_cpy (name, name_size, "ROOT"); |
|
+} |
|
+ |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_convert_integer */ |
|
+/* Description: converts an integer from a null terminated string */ |
|
+/* to der decoding. The convertion from a null */ |
|
+/* terminated string to an integer is made with */ |
|
+/* the 'strtol' function. */ |
|
+/* Parameters: */ |
|
+/* value: null terminated string to convert. */ |
|
+/* value_out: convertion result (memory must be already */ |
|
+/* allocated). */ |
|
+/* value_out_size: number of bytes of value_out. */ |
|
+/* len: number of significant byte of value_out. */ |
|
+/* Return: ASN1_MEM_ERROR or ASN1_SUCCESS */ |
|
+/******************************************************************/ |
|
+int |
|
+_asn1_convert_integer (const unsigned char *value, unsigned char *value_out, |
|
+ int value_out_size, int *len) |
|
+{ |
|
+ char negative; |
|
+ unsigned char val[SIZEOF_UNSIGNED_LONG_INT]; |
|
+ long valtmp; |
|
+ int k, k2; |
|
+ |
|
+ valtmp = _asn1_strtol (value, NULL, 10); |
|
+ |
|
+ for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++) |
|
+ { |
|
+ val[SIZEOF_UNSIGNED_LONG_INT - k - 1] = (valtmp >> (8 * k)) & 0xFF; |
|
+ } |
|
+ |
|
+ if (val[0] & 0x80) |
|
+ negative = 1; |
|
+ else |
|
+ negative = 0; |
|
+ |
|
+ for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT - 1; k++) |
|
+ { |
|
+ if (negative && (val[k] != 0xFF)) |
|
+ break; |
|
+ else if (!negative && val[k]) |
|
+ break; |
|
+ } |
|
+ |
|
+ if ((negative && !(val[k] & 0x80)) || (!negative && (val[k] & 0x80))) |
|
+ k--; |
|
+ |
|
+ *len = SIZEOF_UNSIGNED_LONG_INT - k; |
|
+ |
|
+ if (SIZEOF_UNSIGNED_LONG_INT - k > value_out_size) |
|
+ /* VALUE_OUT is too short to contain the value conversion */ |
|
+ return ASN1_MEM_ERROR; |
|
+ |
|
+ if (value_out != NULL) |
|
+ { |
|
+ for (k2 = k; k2 < SIZEOF_UNSIGNED_LONG_INT; k2++) |
|
+ value_out[k2 - k] = val[k2]; |
|
+ } |
|
+ |
|
+#if 0 |
|
+ printf ("_asn1_convert_integer: valueIn=%s, lenOut=%d", value, *len); |
|
+ for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++) |
|
+ printf (", vOut[%d]=%d", k, value_out[k]); |
|
+ printf ("\n"); |
|
+#endif |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+/* Appends a new element into the sequence (or set) defined by this |
|
+ * node. The new element will have a name of '?number', where number |
|
+ * is a monotonically increased serial number. |
|
+ * |
|
+ * The last element in the list may be provided in @pcache, to avoid |
|
+ * traversing the list, an expensive operation in long lists. |
|
+ * |
|
+ * On success it returns in @pcache the added element (which is the |
|
+ * tail in the list of added elements). |
|
+ */ |
|
+int |
|
+_asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcache) |
|
+{ |
|
+ asn1_node p, p2; |
|
+ char temp[LTOSTR_MAX_SIZE]; |
|
+ long n; |
|
+ |
|
+ if (!node || !(node->down)) |
|
+ return ASN1_GENERIC_ERROR; |
|
+ |
|
+ p = node->down; |
|
+ while ((type_field (p->type) == ASN1_ETYPE_TAG) |
|
+ || (type_field (p->type) == ASN1_ETYPE_SIZE)) |
|
+ p = p->right; |
|
+ |
|
+ p2 = _asn1_copy_structure3 (p); |
|
+ if (p2 == NULL) |
|
+ return ASN1_GENERIC_ERROR; |
|
+ |
|
+ if (pcache == NULL || pcache->tail == NULL || pcache->head != node) |
|
+ { |
|
+ while (p->right) |
|
+ { |
|
+ p = p->right; |
|
+ } |
|
+ } |
|
+ else |
|
+ { |
|
+ p = pcache->tail; |
|
+ } |
|
+ |
|
+ _asn1_set_right (p, p2); |
|
+ if (pcache) |
|
+ { |
|
+ pcache->head = node; |
|
+ pcache->tail = p2; |
|
+ } |
|
+ |
|
+ if (p->name[0] == 0) |
|
+ _asn1_str_cpy (temp, sizeof (temp), "?1"); |
|
+ else |
|
+ { |
|
+ n = strtol (p->name + 1, NULL, 0); |
|
+ n++; |
|
+ temp[0] = '?'; |
|
+ _asn1_ltostr (n, temp + 1); |
|
+ } |
|
+ _asn1_set_name (p2, temp); |
|
+ /* p2->type |= CONST_OPTION; */ |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+ |
|
+/** |
|
+ * asn1_write_value: |
|
+ * @node_root: pointer to a structure |
|
+ * @name: the name of the element inside the structure that you want to set. |
|
+ * @ivalue: vector used to specify the value to set. If len is >0, |
|
+ * VALUE must be a two's complement form integer. if len=0 *VALUE |
|
+ * must be a null terminated string with an integer value. |
|
+ * @len: number of bytes of *value to use to set the value: |
|
+ * value[0]..value[len-1] or 0 if value is a null terminated string |
|
+ * |
|
+ * Set the value of one element inside a structure. |
|
+ * |
|
+ * If an element is OPTIONAL and you want to delete it, you must use |
|
+ * the value=NULL and len=0. Using "pkix.asn": |
|
+ * |
|
+ * result=asn1_write_value(cert, "tbsCertificate.issuerUniqueID", |
|
+ * NULL, 0); |
|
+ * |
|
+ * Description for each type: |
|
+ * |
|
+ * INTEGER: VALUE must contain a two's complement form integer. |
|
+ * |
|
+ * value[0]=0xFF , len=1 -> integer=-1. |
|
+ * value[0]=0xFF value[1]=0xFF , len=2 -> integer=-1. |
|
+ * value[0]=0x01 , len=1 -> integer= 1. |
|
+ * value[0]=0x00 value[1]=0x01 , len=2 -> integer= 1. |
|
+ * value="123" , len=0 -> integer= 123. |
|
+ * |
|
+ * ENUMERATED: As INTEGER (but only with not negative numbers). |
|
+ * |
|
+ * BOOLEAN: VALUE must be the null terminated string "TRUE" or |
|
+ * "FALSE" and LEN != 0. |
|
+ * |
|
+ * value="TRUE" , len=1 -> boolean=TRUE. |
|
+ * value="FALSE" , len=1 -> boolean=FALSE. |
|
+ * |
|
+ * OBJECT IDENTIFIER: VALUE must be a null terminated string with |
|
+ * each number separated by a dot (e.g. "1.2.3.543.1"). LEN != 0. |
|
+ * |
|
+ * value="1 2 840 10040 4 3" , len=1 -> OID=dsa-with-sha. |
|
+ * |
|
+ * UTCTime: VALUE must be a null terminated string in one of these |
|
+ * formats: "YYMMDDhhmmssZ", "YYMMDDhhmmssZ", |
|
+ * "YYMMDDhhmmss+hh'mm'", "YYMMDDhhmmss-hh'mm'", |
|
+ * "YYMMDDhhmm+hh'mm'", or "YYMMDDhhmm-hh'mm'". LEN != 0. |
|
+ * |
|
+ * value="9801011200Z" , len=1 -> time=Jannuary 1st, 1998 |
|
+ * at 12h 00m Greenwich Mean Time |
|
+ * |
|
+ * GeneralizedTime: VALUE must be in one of this format: |
|
+ * "YYYYMMDDhhmmss.sZ", "YYYYMMDDhhmmss.sZ", |
|
+ * "YYYYMMDDhhmmss.s+hh'mm'", "YYYYMMDDhhmmss.s-hh'mm'", |
|
+ * "YYYYMMDDhhmm+hh'mm'", or "YYYYMMDDhhmm-hh'mm'" where ss.s |
|
+ * indicates the seconds with any precision like "10.1" or "01.02". |
|
+ * LEN != 0 |
|
+ * |
|
+ * value="2001010112001.12-0700" , len=1 -> time=Jannuary |
|
+ * 1st, 2001 at 12h 00m 01.12s Pacific Daylight Time |
|
+ * |
|
+ * OCTET STRING: VALUE contains the octet string and LEN is the |
|
+ * number of octets. |
|
+ * |
|
+ * value="$\backslash$x01$\backslash$x02$\backslash$x03" , |
|
+ * len=3 -> three bytes octet string |
|
+ * |
|
+ * GeneralString: VALUE contains the generalstring and LEN is the |
|
+ * number of octets. |
|
+ * |
|
+ * value="$\backslash$x01$\backslash$x02$\backslash$x03" , |
|
+ * len=3 -> three bytes generalstring |
|
+ * |
|
+ * BIT STRING: VALUE contains the bit string organized by bytes and |
|
+ * LEN is the number of bits. |
|
+ * |
|
+ * value="$\backslash$xCF" , len=6 -> bit string="110011" (six |
|
+ * bits) |
|
+ * |
|
+ * CHOICE: if NAME indicates a choice type, VALUE must specify one of |
|
+ * the alternatives with a null terminated string. LEN != 0. Using |
|
+ * "pkix.asn"\: |
|
+ * |
|
+ * result=asn1_write_value(cert, |
|
+ * "certificate1.tbsCertificate.subject", "rdnSequence", |
|
+ * 1); |
|
+ * |
|
+ * ANY: VALUE indicates the der encoding of a structure. LEN != 0. |
|
+ * |
|
+ * SEQUENCE OF: VALUE must be the null terminated string "NEW" and |
|
+ * LEN != 0. With this instruction another element is appended in |
|
+ * the sequence. The name of this element will be "?1" if it's the |
|
+ * first one, "?2" for the second and so on. |
|
+ * |
|
+ * Using "pkix.asn"\: |
|
+ * |
|
+ * result=asn1_write_value(cert, |
|
+ * "certificate1.tbsCertificate.subject.rdnSequence", "NEW", 1); |
|
+ * |
|
+ * SET OF: the same as SEQUENCE OF. Using "pkix.asn": |
|
+ * |
|
+ * result=asn1_write_value(cert, |
|
+ * "tbsCertificate.subject.rdnSequence.?LAST", "NEW", 1); |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if the value was set, |
|
+ * %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element, and |
|
+ * %ASN1_VALUE_NOT_VALID if @ivalue has a wrong format. |
|
+ **/ |
|
+int |
|
+asn1_write_value (asn1_node node_root, const char *name, |
|
+ const void *ivalue, int len) |
|
+{ |
|
+ asn1_node node, p, p2; |
|
+ unsigned char *temp, *value_temp = NULL, *default_temp = NULL; |
|
+ int len2, k, k2, negative; |
|
+ size_t i; |
|
+ const unsigned char *value = ivalue; |
|
+ unsigned int type; |
|
+ |
|
+ node = asn1_find_node (node_root, name); |
|
+ if (node == NULL) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ if ((node->type & CONST_OPTION) && (value == NULL) && (len == 0)) |
|
+ { |
|
+ asn1_delete_structure (&node); |
|
+ return ASN1_SUCCESS; |
|
+ } |
|
+ |
|
+ type = type_field (node->type); |
|
+ |
|
+ if ((type == ASN1_ETYPE_SEQUENCE_OF || type == ASN1_ETYPE_SET_OF) && (value == NULL) && (len == 0)) |
|
+ { |
|
+ p = node->down; |
|
+ while ((type_field (p->type) == ASN1_ETYPE_TAG) |
|
+ || (type_field (p->type) == ASN1_ETYPE_SIZE)) |
|
+ p = p->right; |
|
+ |
|
+ while (p->right) |
|
+ asn1_delete_structure (&p->right); |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+ } |
|
+ |
|
+ /* Don't allow element deletion for other types */ |
|
+ if (value == NULL) |
|
+ { |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ } |
|
+ |
|
+ switch (type) |
|
+ { |
|
+ case ASN1_ETYPE_BOOLEAN: |
|
+ if (!_asn1_strcmp (value, "TRUE")) |
|
+ { |
|
+ if (node->type & CONST_DEFAULT) |
|
+ { |
|
+ p = node->down; |
|
+ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) |
|
+ p = p->right; |
|
+ if (p->type & CONST_TRUE) |
|
+ _asn1_set_value (node, NULL, 0); |
|
+ else |
|
+ _asn1_set_value (node, "T", 1); |
|
+ } |
|
+ else |
|
+ _asn1_set_value (node, "T", 1); |
|
+ } |
|
+ else if (!_asn1_strcmp (value, "FALSE")) |
|
+ { |
|
+ if (node->type & CONST_DEFAULT) |
|
+ { |
|
+ p = node->down; |
|
+ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) |
|
+ p = p->right; |
|
+ if (p->type & CONST_FALSE) |
|
+ _asn1_set_value (node, NULL, 0); |
|
+ else |
|
+ _asn1_set_value (node, "F", 1); |
|
+ } |
|
+ else |
|
+ _asn1_set_value (node, "F", 1); |
|
+ } |
|
+ else |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ break; |
|
+ case ASN1_ETYPE_INTEGER: |
|
+ case ASN1_ETYPE_ENUMERATED: |
|
+ if (len == 0) |
|
+ { |
|
+ if ((c_isdigit (value[0])) || (value[0] == '-')) |
|
+ { |
|
+ value_temp = malloc (SIZEOF_UNSIGNED_LONG_INT); |
|
+ if (value_temp == NULL) |
|
+ return ASN1_MEM_ALLOC_ERROR; |
|
+ |
|
+ _asn1_convert_integer (value, value_temp, |
|
+ SIZEOF_UNSIGNED_LONG_INT, &len); |
|
+ } |
|
+ else |
|
+ { /* is an identifier like v1 */ |
|
+ if (!(node->type & CONST_LIST)) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ p = node->down; |
|
+ while (p) |
|
+ { |
|
+ if (type_field (p->type) == ASN1_ETYPE_CONSTANT) |
|
+ { |
|
+ if (!_asn1_strcmp (p->name, value)) |
|
+ { |
|
+ value_temp = malloc (SIZEOF_UNSIGNED_LONG_INT); |
|
+ if (value_temp == NULL) |
|
+ return ASN1_MEM_ALLOC_ERROR; |
|
+ |
|
+ _asn1_convert_integer (p->value, |
|
+ value_temp, |
|
+ SIZEOF_UNSIGNED_LONG_INT, |
|
+ &len); |
|
+ break; |
|
+ } |
|
+ } |
|
+ p = p->right; |
|
+ } |
|
+ if (p == NULL) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ } |
|
+ } |
|
+ else |
|
+ { /* len != 0 */ |
|
+ value_temp = malloc (len); |
|
+ if (value_temp == NULL) |
|
+ return ASN1_MEM_ALLOC_ERROR; |
|
+ memcpy (value_temp, value, len); |
|
+ } |
|
+ |
|
+ if (value_temp[0] & 0x80) |
|
+ negative = 1; |
|
+ else |
|
+ negative = 0; |
|
+ |
|
+ if (negative && (type_field (node->type) == ASN1_ETYPE_ENUMERATED)) |
|
+ { |
|
+ free (value_temp); |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ } |
|
+ |
|
+ for (k = 0; k < len - 1; k++) |
|
+ if (negative && (value_temp[k] != 0xFF)) |
|
+ break; |
|
+ else if (!negative && value_temp[k]) |
|
+ break; |
|
+ |
|
+ if ((negative && !(value_temp[k] & 0x80)) || |
|
+ (!negative && (value_temp[k] & 0x80))) |
|
+ k--; |
|
+ |
|
+ _asn1_set_value_lv (node, value_temp + k, len - k); |
|
+ |
|
+ if (node->type & CONST_DEFAULT) |
|
+ { |
|
+ p = node->down; |
|
+ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) |
|
+ p = p->right; |
|
+ if ((c_isdigit (p->value[0])) || (p->value[0] == '-')) |
|
+ { |
|
+ default_temp = malloc (SIZEOF_UNSIGNED_LONG_INT); |
|
+ if (default_temp == NULL) |
|
+ { |
|
+ free (value_temp); |
|
+ return ASN1_MEM_ALLOC_ERROR; |
|
+ } |
|
+ |
|
+ _asn1_convert_integer (p->value, default_temp, |
|
+ SIZEOF_UNSIGNED_LONG_INT, &len2); |
|
+ } |
|
+ else |
|
+ { /* is an identifier like v1 */ |
|
+ if (!(node->type & CONST_LIST)) |
|
+ { |
|
+ free (value_temp); |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ } |
|
+ p2 = node->down; |
|
+ while (p2) |
|
+ { |
|
+ if (type_field (p2->type) == ASN1_ETYPE_CONSTANT) |
|
+ { |
|
+ if (!_asn1_strcmp (p2->name, p->value)) |
|
+ { |
|
+ default_temp = malloc (SIZEOF_UNSIGNED_LONG_INT); |
|
+ if (default_temp == NULL) |
|
+ { |
|
+ free (value_temp); |
|
+ return ASN1_MEM_ALLOC_ERROR; |
|
+ } |
|
+ |
|
+ _asn1_convert_integer (p2->value, |
|
+ default_temp, |
|
+ SIZEOF_UNSIGNED_LONG_INT, |
|
+ &len2); |
|
+ break; |
|
+ } |
|
+ } |
|
+ p2 = p2->right; |
|
+ } |
|
+ if (p2 == NULL) |
|
+ { |
|
+ free (value_temp); |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ } |
|
+ } |
|
+ |
|
+ |
|
+ if ((len - k) == len2) |
|
+ { |
|
+ for (k2 = 0; k2 < len2; k2++) |
|
+ if (value_temp[k + k2] != default_temp[k2]) |
|
+ { |
|
+ break; |
|
+ } |
|
+ if (k2 == len2) |
|
+ _asn1_set_value (node, NULL, 0); |
|
+ } |
|
+ free (default_temp); |
|
+ } |
|
+ free (value_temp); |
|
+ break; |
|
+ case ASN1_ETYPE_OBJECT_ID: |
|
+ for (i = 0; i < _asn1_strlen (value); i++) |
|
+ if ((!c_isdigit (value[i])) && (value[i] != '.') && (value[i] != '+')) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ if (node->type & CONST_DEFAULT) |
|
+ { |
|
+ p = node->down; |
|
+ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) |
|
+ p = p->right; |
|
+ if (!_asn1_strcmp (value, p->value)) |
|
+ { |
|
+ _asn1_set_value (node, NULL, 0); |
|
+ break; |
|
+ } |
|
+ } |
|
+ _asn1_set_value (node, value, _asn1_strlen (value) + 1); |
|
+ break; |
|
+ case ASN1_ETYPE_UTC_TIME: |
|
+ { |
|
+ len = _asn1_strlen (value); |
|
+ if (len < 11) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ for (k = 0; k < 10; k++) |
|
+ if (!c_isdigit (value[k])) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ switch (len) |
|
+ { |
|
+ case 11: |
|
+ if (value[10] != 'Z') |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ break; |
|
+ case 13: |
|
+ if ((!c_isdigit (value[10])) || (!c_isdigit (value[11])) || |
|
+ (value[12] != 'Z')) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ break; |
|
+ case 15: |
|
+ if ((value[10] != '+') && (value[10] != '-')) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ for (k = 11; k < 15; k++) |
|
+ if (!c_isdigit (value[k])) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ break; |
|
+ case 17: |
|
+ if ((!c_isdigit (value[10])) || (!c_isdigit (value[11]))) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ if ((value[12] != '+') && (value[12] != '-')) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ for (k = 13; k < 17; k++) |
|
+ if (!c_isdigit (value[k])) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ break; |
|
+ default: |
|
+ return ASN1_VALUE_NOT_FOUND; |
|
+ } |
|
+ _asn1_set_value (node, value, len); |
|
+ } |
|
+ break; |
|
+ case ASN1_ETYPE_GENERALIZED_TIME: |
|
+ len = _asn1_strlen (value); |
|
+ _asn1_set_value (node, value, len); |
|
+ break; |
|
+ case ASN1_ETYPE_OCTET_STRING: |
|
+ case ASN1_ETYPE_GENERALSTRING: |
|
+ case ASN1_ETYPE_NUMERIC_STRING: |
|
+ case ASN1_ETYPE_IA5_STRING: |
|
+ case ASN1_ETYPE_TELETEX_STRING: |
|
+ case ASN1_ETYPE_PRINTABLE_STRING: |
|
+ case ASN1_ETYPE_UNIVERSAL_STRING: |
|
+ case ASN1_ETYPE_BMP_STRING: |
|
+ case ASN1_ETYPE_UTF8_STRING: |
|
+ case ASN1_ETYPE_VISIBLE_STRING: |
|
+ if (len == 0) |
|
+ len = _asn1_strlen (value); |
|
+ _asn1_set_value_lv (node, value, len); |
|
+ break; |
|
+ case ASN1_ETYPE_BIT_STRING: |
|
+ if (len == 0) |
|
+ len = _asn1_strlen (value); |
|
+ asn1_length_der ((len >> 3) + 2, NULL, &len2); |
|
+ temp = malloc ((len >> 3) + 2 + len2); |
|
+ if (temp == NULL) |
|
+ return ASN1_MEM_ALLOC_ERROR; |
|
+ |
|
+ asn1_bit_der (value, len, temp, &len2); |
|
+ _asn1_set_value_m (node, temp, len2); |
|
+ temp = NULL; |
|
+ break; |
|
+ case ASN1_ETYPE_CHOICE: |
|
+ p = node->down; |
|
+ while (p) |
|
+ { |
|
+ if (!_asn1_strcmp (p->name, value)) |
|
+ { |
|
+ p2 = node->down; |
|
+ while (p2) |
|
+ { |
|
+ if (p2 != p) |
|
+ { |
|
+ asn1_delete_structure (&p2); |
|
+ p2 = node->down; |
|
+ } |
|
+ else |
|
+ p2 = p2->right; |
|
+ } |
|
+ break; |
|
+ } |
|
+ p = p->right; |
|
+ } |
|
+ if (!p) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ break; |
|
+ case ASN1_ETYPE_ANY: |
|
+ _asn1_set_value_lv (node, value, len); |
|
+ break; |
|
+ case ASN1_ETYPE_SEQUENCE_OF: |
|
+ case ASN1_ETYPE_SET_OF: |
|
+ if (_asn1_strcmp (value, "NEW")) |
|
+ return ASN1_VALUE_NOT_VALID; |
|
+ _asn1_append_sequence_set (node, NULL); |
|
+ break; |
|
+ default: |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ break; |
|
+ } |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+ |
|
+#define PUT_VALUE( ptr, ptr_size, data, data_size) \ |
|
+ *len = data_size; \ |
|
+ if (ptr_size < data_size) { \ |
|
+ return ASN1_MEM_ERROR; \ |
|
+ } else { \ |
|
+ if (ptr && data_size > 0) \ |
|
+ memcpy (ptr, data, data_size); \ |
|
+ } |
|
+ |
|
+#define PUT_STR_VALUE( ptr, ptr_size, data) \ |
|
+ *len = _asn1_strlen (data) + 1; \ |
|
+ if (ptr_size < *len) { \ |
|
+ return ASN1_MEM_ERROR; \ |
|
+ } else { \ |
|
+ /* this strcpy is checked */ \ |
|
+ if (ptr) { \ |
|
+ _asn1_strcpy (ptr, data); \ |
|
+ } \ |
|
+ } |
|
+ |
|
+#define PUT_AS_STR_VALUE( ptr, ptr_size, data, data_size) \ |
|
+ *len = data_size + 1; \ |
|
+ if (ptr_size < *len) { \ |
|
+ return ASN1_MEM_ERROR; \ |
|
+ } else { \ |
|
+ /* this strcpy is checked */ \ |
|
+ if (ptr) { \ |
|
+ if (data_size > 0) \ |
|
+ memcpy (ptr, data, data_size); \ |
|
+ ptr[data_size] = 0; \ |
|
+ } \ |
|
+ } |
|
+ |
|
+#define ADD_STR_VALUE( ptr, ptr_size, data) \ |
|
+ *len += _asn1_strlen(data); \ |
|
+ if (ptr_size < (int) *len) { \ |
|
+ (*len)++; \ |
|
+ return ASN1_MEM_ERROR; \ |
|
+ } else { \ |
|
+ /* this strcat is checked */ \ |
|
+ if (ptr) _asn1_strcat (ptr, data); \ |
|
+ } |
|
+ |
|
+/** |
|
+ * asn1_read_value: |
|
+ * @root: pointer to a structure. |
|
+ * @name: the name of the element inside a structure that you want to read. |
|
+ * @ivalue: vector that will contain the element's content, must be a |
|
+ * pointer to memory cells already allocated (may be %NULL). |
|
+ * @len: number of bytes of *value: value[0]..value[len-1]. Initialy |
|
+ * holds the sizeof value. |
|
+ * |
|
+ * Returns the value of one element inside a structure. |
|
+ * If an element is OPTIONAL and this returns |
|
+ * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present |
|
+ * in the der encoding that created the structure. The first element |
|
+ * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and |
|
+ * so on. If the @root provided is a node to specific sequence element, |
|
+ * then the keyword "?CURRENT" is also acceptable and indicates the |
|
+ * current sequence element of this node. |
|
+ * |
|
+ * Note that there can be valid values with length zero. In these case |
|
+ * this function will succeed and @len will be zero. |
|
+ * |
|
+ * INTEGER: VALUE will contain a two's complement form integer. |
|
+ * |
|
+ * integer=-1 -> value[0]=0xFF , len=1. |
|
+ * integer=1 -> value[0]=0x01 , len=1. |
|
+ * |
|
+ * ENUMERATED: As INTEGER (but only with not negative numbers). |
|
+ * |
|
+ * BOOLEAN: VALUE will be the null terminated string "TRUE" or |
|
+ * "FALSE" and LEN=5 or LEN=6. |
|
+ * |
|
+ * OBJECT IDENTIFIER: VALUE will be a null terminated string with |
|
+ * each number separated by a dot (i.e. "1.2.3.543.1"). |
|
+ * |
|
+ * LEN = strlen(VALUE)+1 |
|
+ * |
|
+ * UTCTime: VALUE will be a null terminated string in one of these |
|
+ * formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'". |
|
+ * LEN=strlen(VALUE)+1. |
|
+ * |
|
+ * GeneralizedTime: VALUE will be a null terminated string in the |
|
+ * same format used to set the value. |
|
+ * |
|
+ * OCTET STRING: VALUE will contain the octet string and LEN will be |
|
+ * the number of octets. |
|
+ * |
|
+ * GeneralString: VALUE will contain the generalstring and LEN will |
|
+ * be the number of octets. |
|
+ * |
|
+ * BIT STRING: VALUE will contain the bit string organized by bytes |
|
+ * and LEN will be the number of bits. |
|
+ * |
|
+ * CHOICE: If NAME indicates a choice type, VALUE will specify the |
|
+ * alternative selected. |
|
+ * |
|
+ * ANY: If NAME indicates an any type, VALUE will indicate the DER |
|
+ * encoding of the structure actually used. |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if value is returned, |
|
+ * %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element, |
|
+ * %ASN1_VALUE_NOT_FOUND if there isn't any value for the element |
|
+ * selected, and %ASN1_MEM_ERROR if The value vector isn't big enough |
|
+ * to store the result, and in this case @len will contain the number of |
|
+ * bytes needed. On the occasion that the stored data are of zero-length |
|
+ * this function may return %ASN1_SUCCESS even if the provided @len is zero. |
|
+ **/ |
|
+int |
|
+asn1_read_value (asn1_node_const root, const char *name, void *ivalue, int *len) |
|
+{ |
|
+ return asn1_read_value_type (root, name, ivalue, len, NULL); |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_read_value_type: |
|
+ * @root: pointer to a structure. |
|
+ * @name: the name of the element inside a structure that you want to read. |
|
+ * @ivalue: vector that will contain the element's content, must be a |
|
+ * pointer to memory cells already allocated (may be %NULL). |
|
+ * @len: number of bytes of *value: value[0]..value[len-1]. Initialy |
|
+ * holds the sizeof value. |
|
+ * @etype: The type of the value read (ASN1_ETYPE) |
|
+ * |
|
+ * Returns the type and value of one element inside a structure. |
|
+ * If an element is OPTIONAL and this returns |
|
+ * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present |
|
+ * in the der encoding that created the structure. The first element |
|
+ * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and |
|
+ * so on. If the @root provided is a node to specific sequence element, |
|
+ * then the keyword "?CURRENT" is also acceptable and indicates the |
|
+ * current sequence element of this node. |
|
+ * |
|
+ * Note that there can be valid values with length zero. In these case |
|
+ * this function will succeed and @len will be zero. |
|
+ * |
|
+ * |
|
+ * INTEGER: VALUE will contain a two's complement form integer. |
|
+ * |
|
+ * integer=-1 -> value[0]=0xFF , len=1. |
|
+ * integer=1 -> value[0]=0x01 , len=1. |
|
+ * |
|
+ * ENUMERATED: As INTEGER (but only with not negative numbers). |
|
+ * |
|
+ * BOOLEAN: VALUE will be the null terminated string "TRUE" or |
|
+ * "FALSE" and LEN=5 or LEN=6. |
|
+ * |
|
+ * OBJECT IDENTIFIER: VALUE will be a null terminated string with |
|
+ * each number separated by a dot (i.e. "1.2.3.543.1"). |
|
+ * |
|
+ * LEN = strlen(VALUE)+1 |
|
+ * |
|
+ * UTCTime: VALUE will be a null terminated string in one of these |
|
+ * formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'". |
|
+ * LEN=strlen(VALUE)+1. |
|
+ * |
|
+ * GeneralizedTime: VALUE will be a null terminated string in the |
|
+ * same format used to set the value. |
|
+ * |
|
+ * OCTET STRING: VALUE will contain the octet string and LEN will be |
|
+ * the number of octets. |
|
+ * |
|
+ * GeneralString: VALUE will contain the generalstring and LEN will |
|
+ * be the number of octets. |
|
+ * |
|
+ * BIT STRING: VALUE will contain the bit string organized by bytes |
|
+ * and LEN will be the number of bits. |
|
+ * |
|
+ * CHOICE: If NAME indicates a choice type, VALUE will specify the |
|
+ * alternative selected. |
|
+ * |
|
+ * ANY: If NAME indicates an any type, VALUE will indicate the DER |
|
+ * encoding of the structure actually used. |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if value is returned, |
|
+ * %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element, |
|
+ * %ASN1_VALUE_NOT_FOUND if there isn't any value for the element |
|
+ * selected, and %ASN1_MEM_ERROR if The value vector isn't big enough |
|
+ * to store the result, and in this case @len will contain the number of |
|
+ * bytes needed. On the occasion that the stored data are of zero-length |
|
+ * this function may return %ASN1_SUCCESS even if the provided @len is zero. |
|
+ **/ |
|
+int |
|
+asn1_read_value_type (asn1_node_const root, const char *name, void *ivalue, |
|
+ int *len, unsigned int *etype) |
|
+{ |
|
+ asn1_node_const node, p, p2; |
|
+ int len2, len3, result; |
|
+ int value_size = *len; |
|
+ unsigned char *value = ivalue; |
|
+ unsigned type; |
|
+ |
|
+ node = asn1_find_node (root, name); |
|
+ if (node == NULL) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ type = type_field (node->type); |
|
+ |
|
+ if ((type != ASN1_ETYPE_NULL) && |
|
+ (type != ASN1_ETYPE_CHOICE) && |
|
+ !(node->type & CONST_DEFAULT) && !(node->type & CONST_ASSIGN) && |
|
+ (node->value == NULL)) |
|
+ return ASN1_VALUE_NOT_FOUND; |
|
+ |
|
+ if (etype) |
|
+ *etype = type; |
|
+ switch (type) |
|
+ { |
|
+ case ASN1_ETYPE_NULL: |
|
+ PUT_STR_VALUE (value, value_size, "NULL"); |
|
+ break; |
|
+ case ASN1_ETYPE_BOOLEAN: |
|
+ if ((node->type & CONST_DEFAULT) && (node->value == NULL)) |
|
+ { |
|
+ p = node->down; |
|
+ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) |
|
+ p = p->right; |
|
+ if (p->type & CONST_TRUE) |
|
+ { |
|
+ PUT_STR_VALUE (value, value_size, "TRUE"); |
|
+ } |
|
+ else |
|
+ { |
|
+ PUT_STR_VALUE (value, value_size, "FALSE"); |
|
+ } |
|
+ } |
|
+ else if (node->value[0] == 'T') |
|
+ { |
|
+ PUT_STR_VALUE (value, value_size, "TRUE"); |
|
+ } |
|
+ else |
|
+ { |
|
+ PUT_STR_VALUE (value, value_size, "FALSE"); |
|
+ } |
|
+ break; |
|
+ case ASN1_ETYPE_INTEGER: |
|
+ case ASN1_ETYPE_ENUMERATED: |
|
+ if ((node->type & CONST_DEFAULT) && (node->value == NULL)) |
|
+ { |
|
+ p = node->down; |
|
+ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) |
|
+ p = p->right; |
|
+ if ((c_isdigit (p->value[0])) || (p->value[0] == '-') |
|
+ || (p->value[0] == '+')) |
|
+ { |
|
+ result = _asn1_convert_integer |
|
+ (p->value, value, value_size, len); |
|
+ if (result != ASN1_SUCCESS) |
|
+ return result; |
|
+ } |
|
+ else |
|
+ { /* is an identifier like v1 */ |
|
+ p2 = node->down; |
|
+ while (p2) |
|
+ { |
|
+ if (type_field (p2->type) == ASN1_ETYPE_CONSTANT) |
|
+ { |
|
+ if (!_asn1_strcmp (p2->name, p->value)) |
|
+ { |
|
+ result = _asn1_convert_integer |
|
+ (p2->value, value, value_size, |
|
+ len); |
|
+ if (result != ASN1_SUCCESS) |
|
+ return result; |
|
+ break; |
|
+ } |
|
+ } |
|
+ p2 = p2->right; |
|
+ } |
|
+ } |
|
+ } |
|
+ else |
|
+ { |
|
+ len2 = -1; |
|
+ result = asn1_get_octet_der |
|
+ (node->value, node->value_len, &len2, value, value_size, |
|
+ len); |
|
+ if (result != ASN1_SUCCESS) |
|
+ return result; |
|
+ } |
|
+ break; |
|
+ case ASN1_ETYPE_OBJECT_ID: |
|
+ if (node->type & CONST_ASSIGN) |
|
+ { |
|
+ *len = 0; |
|
+ if (value) |
|
+ value[0] = 0; |
|
+ p = node->down; |
|
+ while (p) |
|
+ { |
|
+ if (type_field (p->type) == ASN1_ETYPE_CONSTANT) |
|
+ { |
|
+ ADD_STR_VALUE (value, value_size, p->value); |
|
+ if (p->right) |
|
+ { |
|
+ ADD_STR_VALUE (value, value_size, "."); |
|
+ } |
|
+ } |
|
+ p = p->right; |
|
+ } |
|
+ (*len)++; |
|
+ } |
|
+ else if ((node->type & CONST_DEFAULT) && (node->value == NULL)) |
|
+ { |
|
+ p = node->down; |
|
+ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) |
|
+ p = p->right; |
|
+ PUT_STR_VALUE (value, value_size, p->value); |
|
+ } |
|
+ else |
|
+ { |
|
+ PUT_STR_VALUE (value, value_size, node->value); |
|
+ } |
|
+ break; |
|
+ case ASN1_ETYPE_GENERALIZED_TIME: |
|
+ case ASN1_ETYPE_UTC_TIME: |
|
+ PUT_AS_STR_VALUE (value, value_size, node->value, node->value_len); |
|
+ break; |
|
+ case ASN1_ETYPE_OCTET_STRING: |
|
+ case ASN1_ETYPE_GENERALSTRING: |
|
+ case ASN1_ETYPE_NUMERIC_STRING: |
|
+ case ASN1_ETYPE_IA5_STRING: |
|
+ case ASN1_ETYPE_TELETEX_STRING: |
|
+ case ASN1_ETYPE_PRINTABLE_STRING: |
|
+ case ASN1_ETYPE_UNIVERSAL_STRING: |
|
+ case ASN1_ETYPE_BMP_STRING: |
|
+ case ASN1_ETYPE_UTF8_STRING: |
|
+ case ASN1_ETYPE_VISIBLE_STRING: |
|
+ len2 = -1; |
|
+ result = asn1_get_octet_der |
|
+ (node->value, node->value_len, &len2, value, value_size, |
|
+ len); |
|
+ if (result != ASN1_SUCCESS) |
|
+ return result; |
|
+ break; |
|
+ case ASN1_ETYPE_BIT_STRING: |
|
+ len2 = -1; |
|
+ result = asn1_get_bit_der |
|
+ (node->value, node->value_len, &len2, value, value_size, |
|
+ len); |
|
+ if (result != ASN1_SUCCESS) |
|
+ return result; |
|
+ break; |
|
+ case ASN1_ETYPE_CHOICE: |
|
+ PUT_STR_VALUE (value, value_size, node->down->name); |
|
+ break; |
|
+ case ASN1_ETYPE_ANY: |
|
+ len3 = -1; |
|
+ len2 = asn1_get_length_der (node->value, node->value_len, &len3); |
|
+ if (len2 < 0) |
|
+ return ASN1_DER_ERROR; |
|
+ PUT_VALUE (value, value_size, node->value + len3, len2); |
|
+ break; |
|
+ default: |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ break; |
|
+ } |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+ |
|
+/** |
|
+ * asn1_read_tag: |
|
+ * @root: pointer to a structure |
|
+ * @name: the name of the element inside a structure. |
|
+ * @tagValue: variable that will contain the TAG value. |
|
+ * @classValue: variable that will specify the TAG type. |
|
+ * |
|
+ * Returns the TAG and the CLASS of one element inside a structure. |
|
+ * CLASS can have one of these constants: %ASN1_CLASS_APPLICATION, |
|
+ * %ASN1_CLASS_UNIVERSAL, %ASN1_CLASS_PRIVATE or |
|
+ * %ASN1_CLASS_CONTEXT_SPECIFIC. |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if |
|
+ * @name is not a valid element. |
|
+ **/ |
|
+int |
|
+asn1_read_tag (asn1_node_const root, const char *name, int *tagValue, |
|
+ int *classValue) |
|
+{ |
|
+ asn1_node node, p, pTag; |
|
+ |
|
+ node = asn1_find_node (root, name); |
|
+ if (node == NULL) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ p = node->down; |
|
+ |
|
+ /* pTag will points to the IMPLICIT TAG */ |
|
+ pTag = NULL; |
|
+ if (node->type & CONST_TAG) |
|
+ { |
|
+ while (p) |
|
+ { |
|
+ if (type_field (p->type) == ASN1_ETYPE_TAG) |
|
+ { |
|
+ if ((p->type & CONST_IMPLICIT) && (pTag == NULL)) |
|
+ pTag = p; |
|
+ else if (p->type & CONST_EXPLICIT) |
|
+ pTag = NULL; |
|
+ } |
|
+ p = p->right; |
|
+ } |
|
+ } |
|
+ |
|
+ if (pTag) |
|
+ { |
|
+ *tagValue = _asn1_strtoul (pTag->value, NULL, 10); |
|
+ |
|
+ if (pTag->type & CONST_APPLICATION) |
|
+ *classValue = ASN1_CLASS_APPLICATION; |
|
+ else if (pTag->type & CONST_UNIVERSAL) |
|
+ *classValue = ASN1_CLASS_UNIVERSAL; |
|
+ else if (pTag->type & CONST_PRIVATE) |
|
+ *classValue = ASN1_CLASS_PRIVATE; |
|
+ else |
|
+ *classValue = ASN1_CLASS_CONTEXT_SPECIFIC; |
|
+ } |
|
+ else |
|
+ { |
|
+ unsigned type = type_field (node->type); |
|
+ *classValue = ASN1_CLASS_UNIVERSAL; |
|
+ |
|
+ switch (type) |
|
+ { |
|
+ CASE_HANDLED_ETYPES: |
|
+ *tagValue = _asn1_tags[type].tag; |
|
+ break; |
|
+ case ASN1_ETYPE_TAG: |
|
+ case ASN1_ETYPE_CHOICE: |
|
+ case ASN1_ETYPE_ANY: |
|
+ *tagValue = -1; |
|
+ break; |
|
+ default: |
|
+ break; |
|
+ } |
|
+ } |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_read_node_value: |
|
+ * @node: pointer to a node. |
|
+ * @data: a point to a asn1_data_node_st |
|
+ * |
|
+ * Returns the value a data node inside a asn1_node structure. |
|
+ * The data returned should be handled as constant values. |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if the node exists. |
|
+ **/ |
|
+int |
|
+asn1_read_node_value (asn1_node_const node, asn1_data_node_st * data) |
|
+{ |
|
+ data->name = node->name; |
|
+ data->value = node->value; |
|
+ data->value_len = node->value_len; |
|
+ data->type = type_field (node->type); |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
diff --git a/grub-core/lib/libtasn1/lib/errors.c b/grub-core/lib/libtasn1/lib/errors.c |
|
new file mode 100644 |
|
index 00000000000..cee74daf795 |
|
--- /dev/null |
|
+++ b/grub-core/lib/libtasn1/lib/errors.c |
|
@@ -0,0 +1,100 @@ |
|
+/* |
|
+ * Copyright (C) 2002-2014 Free Software Foundation, Inc. |
|
+ * |
|
+ * This file is part of LIBTASN1. |
|
+ * |
|
+ * The LIBTASN1 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 Street, Fifth Floor, Boston, MA |
|
+ * 02110-1301, USA |
|
+ */ |
|
+ |
|
+#include <int.h> |
|
+#ifdef STDC_HEADERS |
|
+#include <stdarg.h> |
|
+#endif |
|
+ |
|
+#define LIBTASN1_ERROR_ENTRY(name) { #name, name } |
|
+ |
|
+struct libtasn1_error_entry |
|
+{ |
|
+ const char *name; |
|
+ int number; |
|
+}; |
|
+typedef struct libtasn1_error_entry libtasn1_error_entry; |
|
+ |
|
+static const libtasn1_error_entry error_algorithms[] = { |
|
+ LIBTASN1_ERROR_ENTRY (ASN1_SUCCESS), |
|
+ LIBTASN1_ERROR_ENTRY (ASN1_FILE_NOT_FOUND), |
|
+ LIBTASN1_ERROR_ENTRY (ASN1_ELEMENT_NOT_FOUND), |
|
+ LIBTASN1_ERROR_ENTRY (ASN1_IDENTIFIER_NOT_FOUND), |
|
+ LIBTASN1_ERROR_ENTRY (ASN1_DER_ERROR), |
|
+ LIBTASN1_ERROR_ENTRY (ASN1_VALUE_NOT_FOUND), |
|
+ LIBTASN1_ERROR_ENTRY (ASN1_GENERIC_ERROR), |
|
+ LIBTASN1_ERROR_ENTRY (ASN1_VALUE_NOT_VALID), |
|
+ LIBTASN1_ERROR_ENTRY (ASN1_TAG_ERROR), |
|
+ LIBTASN1_ERROR_ENTRY (ASN1_TAG_IMPLICIT), |
|
+ LIBTASN1_ERROR_ENTRY (ASN1_ERROR_TYPE_ANY), |
|
+ LIBTASN1_ERROR_ENTRY (ASN1_SYNTAX_ERROR), |
|
+ LIBTASN1_ERROR_ENTRY (ASN1_MEM_ERROR), |
|
+ LIBTASN1_ERROR_ENTRY (ASN1_MEM_ALLOC_ERROR), |
|
+ LIBTASN1_ERROR_ENTRY (ASN1_DER_OVERFLOW), |
|
+ LIBTASN1_ERROR_ENTRY (ASN1_NAME_TOO_LONG), |
|
+ LIBTASN1_ERROR_ENTRY (ASN1_ARRAY_ERROR), |
|
+ LIBTASN1_ERROR_ENTRY (ASN1_ELEMENT_NOT_EMPTY), |
|
+ LIBTASN1_ERROR_ENTRY (ASN1_TIME_ENCODING_ERROR), |
|
+ LIBTASN1_ERROR_ENTRY (ASN1_RECURSION), |
|
+ {0, 0} |
|
+}; |
|
+ |
|
+/** |
|
+ * asn1_perror: |
|
+ * @error: is an error returned by a libtasn1 function. |
|
+ * |
|
+ * Prints a string to stderr with a description of an error. This |
|
+ * function is like perror(). The only difference is that it accepts |
|
+ * an error returned by a libtasn1 function. |
|
+ * |
|
+ * Since: 1.6 |
|
+ **/ |
|
+void |
|
+asn1_perror (int error) |
|
+{ |
|
+ const char *str = asn1_strerror (error); |
|
+ fprintf (stderr, "LIBTASN1 ERROR: %s\n", str ? str : "(null)"); |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_strerror: |
|
+ * @error: is an error returned by a libtasn1 function. |
|
+ * |
|
+ * Returns a string with a description of an error. This function is |
|
+ * similar to strerror. The only difference is that it accepts an |
|
+ * error (number) returned by a libtasn1 function. |
|
+ * |
|
+ * Returns: Pointer to static zero-terminated string describing error |
|
+ * code. |
|
+ * |
|
+ * Since: 1.6 |
|
+ **/ |
|
+const char * |
|
+asn1_strerror (int error) |
|
+{ |
|
+ const libtasn1_error_entry *p; |
|
+ |
|
+ for (p = error_algorithms; p->name != NULL; p++) |
|
+ if (p->number == error) |
|
+ return p->name + sizeof ("ASN1_") - 1; |
|
+ |
|
+ return NULL; |
|
+} |
|
diff --git a/grub-core/lib/libtasn1/lib/gstr.c b/grub-core/lib/libtasn1/lib/gstr.c |
|
new file mode 100644 |
|
index 00000000000..e91a3a151c0 |
|
--- /dev/null |
|
+++ b/grub-core/lib/libtasn1/lib/gstr.c |
|
@@ -0,0 +1,74 @@ |
|
+/* |
|
+ * Copyright (C) 2002-2014 Free Software Foundation, Inc. |
|
+ * |
|
+ * This file is part of LIBTASN1. |
|
+ * |
|
+ * The LIBTASN1 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 Street, Fifth Floor, Boston, MA |
|
+ * 02110-1301, USA |
|
+ */ |
|
+ |
|
+#include <int.h> |
|
+#include "gstr.h" |
|
+ |
|
+/* These function are like strcat, strcpy. They only |
|
+ * do bounds checking (they shouldn't cause buffer overruns), |
|
+ * and they always produce null terminated strings. |
|
+ * |
|
+ * They should be used only with null terminated strings. |
|
+ */ |
|
+void |
|
+_asn1_str_cat (char *dest, size_t dest_tot_size, const char *src) |
|
+{ |
|
+ size_t str_size = strlen (src); |
|
+ size_t dest_size = strlen (dest); |
|
+ |
|
+ if (dest_tot_size - dest_size > str_size) |
|
+ { |
|
+ strcat (dest, src); |
|
+ } |
|
+ else |
|
+ { |
|
+ if (dest_tot_size - dest_size > 0) |
|
+ { |
|
+ strncat (dest, src, (dest_tot_size - dest_size) - 1); |
|
+ dest[dest_tot_size - 1] = 0; |
|
+ } |
|
+ } |
|
+} |
|
+ |
|
+/* Returns the bytes copied (not including the null terminator) */ |
|
+unsigned int |
|
+_asn1_str_cpy (char *dest, size_t dest_tot_size, const char *src) |
|
+{ |
|
+ size_t str_size = strlen (src); |
|
+ |
|
+ if (dest_tot_size > str_size) |
|
+ { |
|
+ strcpy (dest, src); |
|
+ return str_size; |
|
+ } |
|
+ else |
|
+ { |
|
+ if (dest_tot_size > 0) |
|
+ { |
|
+ str_size = dest_tot_size - 1; |
|
+ memcpy (dest, src, str_size); |
|
+ dest[str_size] = 0; |
|
+ return str_size; |
|
+ } |
|
+ else |
|
+ return 0; |
|
+ } |
|
+} |
|
diff --git a/grub-core/lib/libtasn1/lib/parser_aux.c b/grub-core/lib/libtasn1/lib/parser_aux.c |
|
new file mode 100644 |
|
index 00000000000..d5dbbf8765d |
|
--- /dev/null |
|
+++ b/grub-core/lib/libtasn1/lib/parser_aux.c |
|
@@ -0,0 +1,1173 @@ |
|
+/* |
|
+ * Copyright (C) 2000-2016 Free Software Foundation, Inc. |
|
+ * |
|
+ * This file is part of LIBTASN1. |
|
+ * |
|
+ * The LIBTASN1 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 Street, Fifth Floor, Boston, MA |
|
+ * 02110-1301, USA |
|
+ */ |
|
+ |
|
+#include <limits.h> // WORD_BIT |
|
+ |
|
+#include "int.h" |
|
+#include "parser_aux.h" |
|
+#include "gstr.h" |
|
+#include "structure.h" |
|
+#include "element.h" |
|
+#include "c-ctype.h" |
|
+ |
|
+char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1]; /* identifier name not found */ |
|
+ |
|
+/* Return a hash of the N bytes of X using the method described by |
|
+ Bruno Haible in https://www.haible.de/bruno/hashfunc.html. |
|
+ Note that while many hash functions reduce their result via modulo |
|
+ to a 0..table_size-1 range, this function does not do that. |
|
+ |
|
+ This implementation has been changed from size_t -> unsigned int. */ |
|
+ |
|
+#ifdef __clang__ |
|
+__attribute__((no_sanitize("integer"))) |
|
+#endif |
|
+_GL_ATTRIBUTE_PURE |
|
+static unsigned int |
|
+_asn1_hash_name (const char *x) |
|
+{ |
|
+ const unsigned char *s = (unsigned char *) x; |
|
+ unsigned h = 0; |
|
+ |
|
+ while (*s) |
|
+ h = (*s++) + ((h << 9) | (h >> (WORD_BIT - 9))); |
|
+ |
|
+ return h; |
|
+} |
|
+ |
|
+/******************************************************/ |
|
+/* Function : _asn1_add_static_node */ |
|
+/* Description: creates a new NODE_ASN element and */ |
|
+/* puts it in the list pointed by e_list. */ |
|
+/* Parameters: */ |
|
+/* e_list: of type list_type; must be NULL initially */ |
|
+/* type: type of the new element (see ASN1_ETYPE_ */ |
|
+/* and CONST_ constants). */ |
|
+/* Return: pointer to the new element. */ |
|
+/******************************************************/ |
|
+asn1_node |
|
+_asn1_add_static_node (list_type **e_list, unsigned int type) |
|
+{ |
|
+ list_type *p; |
|
+ asn1_node punt; |
|
+ |
|
+ punt = calloc (1, sizeof (struct asn1_node_st)); |
|
+ if (punt == NULL) |
|
+ return NULL; |
|
+ |
|
+ p = malloc (sizeof (list_type)); |
|
+ if (p == NULL) |
|
+ { |
|
+ free (punt); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ p->node = punt; |
|
+ p->next = *e_list; |
|
+ *e_list = p; |
|
+ |
|
+ punt->type = type; |
|
+ |
|
+ return punt; |
|
+} |
|
+ |
|
+static |
|
+int _asn1_add_static_node2 (list_type **e_list, asn1_node node) |
|
+{ |
|
+ list_type *p; |
|
+ |
|
+ p = malloc (sizeof (list_type)); |
|
+ if (p == NULL) |
|
+ { |
|
+ return -1; |
|
+ } |
|
+ |
|
+ p->node = node; |
|
+ p->next = *e_list; |
|
+ *e_list = p; |
|
+ |
|
+ return 0; |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_find_node: |
|
+ * @pointer: NODE_ASN element pointer. |
|
+ * @name: null terminated string with the element's name to find. |
|
+ * |
|
+ * Searches for an element called @name starting from @pointer. The |
|
+ * name is composed by different identifiers separated by dots. When |
|
+ * *@pointer has a name, the first identifier must be the name of |
|
+ * *@pointer, otherwise it must be the name of one child of *@pointer. |
|
+ * |
|
+ * Returns: the search result, or %NULL if not found. |
|
+ **/ |
|
+asn1_node |
|
+asn1_find_node (asn1_node_const pointer, const char *name) |
|
+{ |
|
+ asn1_node_const p; |
|
+ char *n_end, n[ASN1_MAX_NAME_SIZE + 1]; |
|
+ const char *n_start; |
|
+ unsigned int nsize; |
|
+ unsigned int nhash; |
|
+ |
|
+ if (pointer == NULL) |
|
+ return NULL; |
|
+ |
|
+ if (name == NULL) |
|
+ return NULL; |
|
+ |
|
+ p = pointer; |
|
+ n_start = name; |
|
+ |
|
+ if (name[0] == '?' && name[1] == 'C' && p->name[0] == '?') |
|
+ { /* ?CURRENT */ |
|
+ n_start = strchr(n_start, '.'); |
|
+ if (n_start) |
|
+ n_start++; |
|
+ } |
|
+ else if (p->name[0] != 0) |
|
+ { /* has *pointer got a name ? */ |
|
+ n_end = strchr (n_start, '.'); /* search the first dot */ |
|
+ if (n_end) |
|
+ { |
|
+ nsize = n_end - n_start; |
|
+ if (nsize >= sizeof(n)) |
|
+ return NULL; |
|
+ |
|
+ memcpy (n, n_start, nsize); |
|
+ n[nsize] = 0; |
|
+ n_start = n_end; |
|
+ n_start++; |
|
+ |
|
+ nhash = _asn1_hash_name (n); |
|
+ } |
|
+ else |
|
+ { |
|
+ _asn1_str_cpy (n, sizeof (n), n_start); |
|
+ nhash = _asn1_hash_name (n); |
|
+ |
|
+ n_start = NULL; |
|
+ } |
|
+ |
|
+ while (p) |
|
+ { |
|
+ if (nhash == p->name_hash && (!strcmp (p->name, n))) |
|
+ break; |
|
+ else |
|
+ p = p->right; |
|
+ } /* while */ |
|
+ |
|
+ if (p == NULL) |
|
+ return NULL; |
|
+ } |
|
+ else |
|
+ { /* *pointer doesn't have a name */ |
|
+ if (n_start[0] == 0) |
|
+ return (asn1_node) p; |
|
+ } |
|
+ |
|
+ while (n_start) |
|
+ { /* Has the end of NAME been reached? */ |
|
+ n_end = strchr (n_start, '.'); /* search the next dot */ |
|
+ if (n_end) |
|
+ { |
|
+ nsize = n_end - n_start; |
|
+ if (nsize >= sizeof(n)) |
|
+ return NULL; |
|
+ |
|
+ memcpy (n, n_start, nsize); |
|
+ n[nsize] = 0; |
|
+ n_start = n_end; |
|
+ n_start++; |
|
+ |
|
+ nhash = _asn1_hash_name (n); |
|
+ } |
|
+ else |
|
+ { |
|
+ _asn1_str_cpy (n, sizeof (n), n_start); |
|
+ nhash = _asn1_hash_name (n); |
|
+ n_start = NULL; |
|
+ } |
|
+ |
|
+ if (p->down == NULL) |
|
+ return NULL; |
|
+ |
|
+ p = p->down; |
|
+ if (p == NULL) |
|
+ return NULL; |
|
+ |
|
+ /* The identifier "?LAST" indicates the last element |
|
+ in the right chain. */ |
|
+ if (n[0] == '?' && n[1] == 'L') /* ?LAST */ |
|
+ { |
|
+ while (p->right) |
|
+ p = p->right; |
|
+ } |
|
+ else |
|
+ { /* no "?LAST" */ |
|
+ while (p) |
|
+ { |
|
+ if (p->name_hash == nhash && !strcmp (p->name, n)) |
|
+ break; |
|
+ else |
|
+ p = p->right; |
|
+ } |
|
+ } |
|
+ if (p == NULL) |
|
+ return NULL; |
|
+ } /* while */ |
|
+ |
|
+ return (asn1_node) p; |
|
+} |
|
+ |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_set_value */ |
|
+/* Description: sets the field VALUE in a NODE_ASN element. The */ |
|
+/* previous value (if exist) will be lost */ |
|
+/* Parameters: */ |
|
+/* node: element pointer. */ |
|
+/* value: pointer to the value that you want to set. */ |
|
+/* len: character number of value. */ |
|
+/* Return: pointer to the NODE_ASN element. */ |
|
+/******************************************************************/ |
|
+asn1_node |
|
+_asn1_set_value (asn1_node node, const void *value, unsigned int len) |
|
+{ |
|
+ if (node == NULL) |
|
+ return node; |
|
+ if (node->value) |
|
+ { |
|
+ if (node->value != node->small_value) |
|
+ free (node->value); |
|
+ node->value = NULL; |
|
+ node->value_len = 0; |
|
+ } |
|
+ |
|
+ if (!len) |
|
+ return node; |
|
+ |
|
+ if (len < sizeof (node->small_value)) |
|
+ { |
|
+ node->value = node->small_value; |
|
+ } |
|
+ else |
|
+ { |
|
+ node->value = malloc (len); |
|
+ if (node->value == NULL) |
|
+ return NULL; |
|
+ } |
|
+ node->value_len = len; |
|
+ |
|
+ memcpy (node->value, value, len); |
|
+ return node; |
|
+} |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_set_value_lv */ |
|
+/* Description: sets the field VALUE in a NODE_ASN element. The */ |
|
+/* previous value (if exist) will be lost. The value */ |
|
+/* given is stored as an length-value format (LV */ |
|
+/* Parameters: */ |
|
+/* node: element pointer. */ |
|
+/* value: pointer to the value that you want to set. */ |
|
+/* len: character number of value. */ |
|
+/* Return: pointer to the NODE_ASN element. */ |
|
+/******************************************************************/ |
|
+asn1_node |
|
+_asn1_set_value_lv (asn1_node node, const void *value, unsigned int len) |
|
+{ |
|
+ int len2; |
|
+ void *temp; |
|
+ |
|
+ if (node == NULL) |
|
+ return node; |
|
+ |
|
+ asn1_length_der (len, NULL, &len2); |
|
+ temp = malloc (len + len2); |
|
+ if (temp == NULL) |
|
+ return NULL; |
|
+ |
|
+ asn1_octet_der (value, len, temp, &len2); |
|
+ return _asn1_set_value_m (node, temp, len2); |
|
+} |
|
+ |
|
+/* the same as _asn1_set_value except that it sets an already malloc'ed |
|
+ * value. |
|
+ */ |
|
+asn1_node |
|
+_asn1_set_value_m (asn1_node node, void *value, unsigned int len) |
|
+{ |
|
+ if (node == NULL) |
|
+ return node; |
|
+ |
|
+ if (node->value) |
|
+ { |
|
+ if (node->value != node->small_value) |
|
+ free (node->value); |
|
+ node->value = NULL; |
|
+ node->value_len = 0; |
|
+ } |
|
+ |
|
+ if (!len) |
|
+ return node; |
|
+ |
|
+ node->value = value; |
|
+ node->value_len = len; |
|
+ |
|
+ return node; |
|
+} |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_append_value */ |
|
+/* Description: appends to the field VALUE in a NODE_ASN element. */ |
|
+/* */ |
|
+/* Parameters: */ |
|
+/* node: element pointer. */ |
|
+/* value: pointer to the value that you want to be appended. */ |
|
+/* len: character number of value. */ |
|
+/* Return: pointer to the NODE_ASN element. */ |
|
+/******************************************************************/ |
|
+asn1_node |
|
+_asn1_append_value (asn1_node node, const void *value, unsigned int len) |
|
+{ |
|
+ if (node == NULL) |
|
+ return node; |
|
+ |
|
+ if (node->value == NULL) |
|
+ return _asn1_set_value (node, value, len); |
|
+ |
|
+ if (len == 0) |
|
+ return node; |
|
+ |
|
+ if (node->value == node->small_value) |
|
+ { |
|
+ /* value is in node */ |
|
+ int prev_len = node->value_len; |
|
+ node->value_len += len; |
|
+ node->value = malloc (node->value_len); |
|
+ if (node->value == NULL) |
|
+ { |
|
+ node->value_len = 0; |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ if (prev_len > 0) |
|
+ memcpy (node->value, node->small_value, prev_len); |
|
+ |
|
+ memcpy (&node->value[prev_len], value, len); |
|
+ |
|
+ return node; |
|
+ } |
|
+ else /* if (node->value != NULL && node->value != node->small_value) */ |
|
+ { |
|
+ /* value is allocated */ |
|
+ int prev_len = node->value_len; |
|
+ node->value_len += len; |
|
+ |
|
+ node->value = _asn1_realloc (node->value, node->value_len); |
|
+ if (node->value == NULL) |
|
+ { |
|
+ node->value_len = 0; |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ memcpy (&node->value[prev_len], value, len); |
|
+ |
|
+ return node; |
|
+ } |
|
+} |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_set_name */ |
|
+/* Description: sets the field NAME in a NODE_ASN element. The */ |
|
+/* previous value (if exist) will be lost */ |
|
+/* Parameters: */ |
|
+/* node: element pointer. */ |
|
+/* name: a null terminated string with the name that you want */ |
|
+/* to set. */ |
|
+/* Return: pointer to the NODE_ASN element. */ |
|
+/******************************************************************/ |
|
+asn1_node |
|
+_asn1_set_name (asn1_node node, const char *name) |
|
+{ |
|
+ if (node == NULL) |
|
+ return node; |
|
+ |
|
+ _asn1_str_cpy (node->name, sizeof (node->name), name ? name : ""); |
|
+ node->name_hash = _asn1_hash_name (node->name); |
|
+ |
|
+ return node; |
|
+} |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_cpy_name */ |
|
+/* Description: copies the field NAME in a NODE_ASN element. */ |
|
+/* Parameters: */ |
|
+/* dst: a dest element pointer. */ |
|
+/* src: a source element pointer. */ |
|
+/* Return: pointer to the NODE_ASN element. */ |
|
+/******************************************************************/ |
|
+asn1_node |
|
+_asn1_cpy_name (asn1_node dst, asn1_node_const src) |
|
+{ |
|
+ if (dst == NULL) |
|
+ return dst; |
|
+ |
|
+ if (src == NULL) |
|
+ { |
|
+ dst->name[0] = 0; |
|
+ dst->name_hash = _asn1_hash_name (dst->name); |
|
+ return dst; |
|
+ } |
|
+ |
|
+ _asn1_str_cpy (dst->name, sizeof (dst->name), src->name); |
|
+ dst->name_hash = src->name_hash; |
|
+ |
|
+ return dst; |
|
+} |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_set_right */ |
|
+/* Description: sets the field RIGHT in a NODE_ASN element. */ |
|
+/* Parameters: */ |
|
+/* node: element pointer. */ |
|
+/* right: pointer to a NODE_ASN element that you want be pointed*/ |
|
+/* by NODE. */ |
|
+/* Return: pointer to *NODE. */ |
|
+/******************************************************************/ |
|
+asn1_node |
|
+_asn1_set_right (asn1_node node, asn1_node right) |
|
+{ |
|
+ if (node == NULL) |
|
+ return node; |
|
+ node->right = right; |
|
+ if (right) |
|
+ right->left = node; |
|
+ return node; |
|
+} |
|
+ |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_get_last_right */ |
|
+/* Description: return the last element along the right chain. */ |
|
+/* Parameters: */ |
|
+/* node: starting element pointer. */ |
|
+/* Return: pointer to the last element along the right chain. */ |
|
+/******************************************************************/ |
|
+asn1_node |
|
+_asn1_get_last_right (asn1_node_const node) |
|
+{ |
|
+ asn1_node_const p; |
|
+ |
|
+ if (node == NULL) |
|
+ return NULL; |
|
+ p = node; |
|
+ while (p->right) |
|
+ p = p->right; |
|
+ return (asn1_node) p; |
|
+} |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_remove_node */ |
|
+/* Description: gets free the memory allocated for an NODE_ASN */ |
|
+/* element (not the elements pointed by it). */ |
|
+/* Parameters: */ |
|
+/* node: NODE_ASN element pointer. */ |
|
+/* flags: ASN1_DELETE_FLAG_* */ |
|
+/******************************************************************/ |
|
+void |
|
+_asn1_remove_node (asn1_node node, unsigned int flags) |
|
+{ |
|
+ if (node == NULL) |
|
+ return; |
|
+ |
|
+ if (node->value != NULL) |
|
+ { |
|
+ if (flags & ASN1_DELETE_FLAG_ZEROIZE) |
|
+ { |
|
+ safe_memset(node->value, 0, node->value_len); |
|
+ } |
|
+ |
|
+ if (node->value != node->small_value) |
|
+ free (node->value); |
|
+ } |
|
+ free (node); |
|
+} |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_find_up */ |
|
+/* Description: return the father of the NODE_ASN element. */ |
|
+/* Parameters: */ |
|
+/* node: NODE_ASN element pointer. */ |
|
+/* Return: Null if not found. */ |
|
+/******************************************************************/ |
|
+asn1_node |
|
+_asn1_find_up (asn1_node_const node) |
|
+{ |
|
+ asn1_node_const p; |
|
+ |
|
+ if (node == NULL) |
|
+ return NULL; |
|
+ |
|
+ p = node; |
|
+ |
|
+ while ((p->left != NULL) && (p->left->right == p)) |
|
+ p = p->left; |
|
+ |
|
+ return p->left; |
|
+} |
|
+ |
|
+static |
|
+unsigned _asn1_is_up (asn1_node_const up_cand, asn1_node_const down) |
|
+{ |
|
+ asn1_node_const d, u; |
|
+ |
|
+ if (up_cand == NULL || down == NULL) |
|
+ return 0; |
|
+ |
|
+ d = down; |
|
+ |
|
+ while ((u = _asn1_find_up(d)) != NULL && u != d) |
|
+ { |
|
+ if (u == up_cand) |
|
+ return 1; |
|
+ d = u; |
|
+ } |
|
+ |
|
+ return 0; |
|
+} |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_delete_node_from_list */ |
|
+/* Description: deletes the list element given */ |
|
+/******************************************************************/ |
|
+void |
|
+_asn1_delete_node_from_list (list_type *list, asn1_node node) |
|
+{ |
|
+ list_type *p = list; |
|
+ |
|
+ while (p) |
|
+ { |
|
+ if (p->node == node) |
|
+ p->node = NULL; |
|
+ p = p->next; |
|
+ } |
|
+} |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_delete_list */ |
|
+/* Description: deletes the list elements (not the elements */ |
|
+/* pointed by them). */ |
|
+/******************************************************************/ |
|
+void |
|
+_asn1_delete_list (list_type *e_list) |
|
+{ |
|
+ list_type *p; |
|
+ |
|
+ while (e_list) |
|
+ { |
|
+ p = e_list; |
|
+ e_list = e_list->next; |
|
+ free (p); |
|
+ } |
|
+} |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_delete_list_and nodes */ |
|
+/* Description: deletes the list elements and the elements */ |
|
+/* pointed by them. */ |
|
+/******************************************************************/ |
|
+void |
|
+_asn1_delete_list_and_nodes (list_type *e_list) |
|
+{ |
|
+ list_type *p; |
|
+ |
|
+ while (e_list) |
|
+ { |
|
+ p = e_list; |
|
+ e_list = e_list->next; |
|
+ _asn1_remove_node (p->node, 0); |
|
+ free (p); |
|
+ } |
|
+} |
|
+ |
|
+ |
|
+char * |
|
+_asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE]) |
|
+{ |
|
+ uint64_t d, r; |
|
+ char temp[LTOSTR_MAX_SIZE]; |
|
+ int count, k, start; |
|
+ uint64_t val; |
|
+ |
|
+ if (v < 0) |
|
+ { |
|
+ str[0] = '-'; |
|
+ start = 1; |
|
+ val = -((uint64_t)v); |
|
+ } |
|
+ else |
|
+ { |
|
+ val = v; |
|
+ start = 0; |
|
+ } |
|
+ |
|
+ count = 0; |
|
+ do |
|
+ { |
|
+ d = val / 10; |
|
+ r = val - d * 10; |
|
+ temp[start + count] = '0' + (char) r; |
|
+ count++; |
|
+ val = d; |
|
+ } |
|
+ while (val && ((start+count) < LTOSTR_MAX_SIZE-1)); |
|
+ |
|
+ for (k = 0; k < count; k++) |
|
+ str[k + start] = temp[start + count - k - 1]; |
|
+ str[count + start] = 0; |
|
+ return str; |
|
+} |
|
+ |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_change_integer_value */ |
|
+/* Description: converts into DER coding the value assign to an */ |
|
+/* INTEGER constant. */ |
|
+/* Parameters: */ |
|
+/* node: root of an ASN1element. */ |
|
+/* Return: */ |
|
+/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ |
|
+/* otherwise ASN1_SUCCESS */ |
|
+/******************************************************************/ |
|
+int |
|
+_asn1_change_integer_value (asn1_node node) |
|
+{ |
|
+ asn1_node p; |
|
+ unsigned char val[SIZEOF_UNSIGNED_LONG_INT]; |
|
+ unsigned char val2[SIZEOF_UNSIGNED_LONG_INT + 1]; |
|
+ int len; |
|
+ |
|
+ if (node == NULL) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ p = node; |
|
+ while (p) |
|
+ { |
|
+ if ((type_field (p->type) == ASN1_ETYPE_INTEGER) |
|
+ && (p->type & CONST_ASSIGN)) |
|
+ { |
|
+ if (p->value) |
|
+ { |
|
+ _asn1_convert_integer (p->value, val, sizeof (val), &len); |
|
+ asn1_octet_der (val, len, val2, &len); |
|
+ _asn1_set_value (p, val2, len); |
|
+ } |
|
+ } |
|
+ |
|
+ if (p->down) |
|
+ { |
|
+ p = p->down; |
|
+ } |
|
+ else |
|
+ { |
|
+ if (p == node) |
|
+ p = NULL; |
|
+ else if (p->right) |
|
+ p = p->right; |
|
+ else |
|
+ { |
|
+ while (1) |
|
+ { |
|
+ p = _asn1_find_up (p); |
|
+ if (p == node) |
|
+ { |
|
+ p = NULL; |
|
+ break; |
|
+ } |
|
+ if (p && p->right) |
|
+ { |
|
+ p = p->right; |
|
+ break; |
|
+ } |
|
+ } |
|
+ } |
|
+ } |
|
+ } |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+#define MAX_CONSTANTS 1024 |
|
+/******************************************************************/ |
|
+/* Function : _asn1_expand_object_id */ |
|
+/* Description: expand the IDs of an OBJECT IDENTIFIER constant. */ |
|
+/* Parameters: */ |
|
+/* list: root of an object list */ |
|
+/* node: root of an ASN1 element. */ |
|
+/* Return: */ |
|
+/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ |
|
+/* otherwise ASN1_SUCCESS */ |
|
+/******************************************************************/ |
|
+int |
|
+_asn1_expand_object_id (list_type **list, asn1_node node) |
|
+{ |
|
+ asn1_node p, p2, p3, p4, p5; |
|
+ char name_root[ASN1_MAX_NAME_SIZE], name2[2 * ASN1_MAX_NAME_SIZE + 1]; |
|
+ int move, tlen, tries; |
|
+ unsigned max_constants; |
|
+ |
|
+ if (node == NULL) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ _asn1_str_cpy (name_root, sizeof (name_root), node->name); |
|
+ |
|
+ p = node; |
|
+ move = DOWN; |
|
+ tries = 0; |
|
+ |
|
+ while (!((p == node) && (move == UP))) |
|
+ { |
|
+ if (move != UP) |
|
+ { |
|
+ if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) |
|
+ && (p->type & CONST_ASSIGN)) |
|
+ { |
|
+ p2 = p->down; |
|
+ if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT)) |
|
+ { |
|
+ if (p2->value && !c_isdigit (p2->value[0])) |
|
+ { |
|
+ _asn1_str_cpy (name2, sizeof (name2), name_root); |
|
+ _asn1_str_cat (name2, sizeof (name2), "."); |
|
+ _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); |
|
+ p3 = asn1_find_node (node, name2); |
|
+ if (!p3 || _asn1_is_up(p2, p3) || |
|
+ (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) || |
|
+ !(p3->type & CONST_ASSIGN)) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ _asn1_set_down (p, p2->right); |
|
+ if (p2->down) |
|
+ _asn1_delete_structure (*list, &p2->down, 0); |
|
+ _asn1_delete_node_from_list(*list, p2); |
|
+ _asn1_remove_node (p2, 0); |
|
+ p2 = p; |
|
+ p4 = p3->down; |
|
+ max_constants = 0; |
|
+ while (p4) |
|
+ { |
|
+ if (type_field (p4->type) == ASN1_ETYPE_CONSTANT) |
|
+ { |
|
+ max_constants++; |
|
+ if (max_constants == MAX_CONSTANTS) |
|
+ return ASN1_RECURSION; |
|
+ |
|
+ p5 = |
|
+ _asn1_add_single_node (ASN1_ETYPE_CONSTANT); |
|
+ _asn1_set_name (p5, p4->name); |
|
+ if (p4->value) |
|
+ { |
|
+ tlen = _asn1_strlen (p4->value); |
|
+ if (tlen > 0) |
|
+ _asn1_set_value (p5, p4->value, tlen + 1); |
|
+ } |
|
+ _asn1_add_static_node2(list, p5); |
|
+ |
|
+ if (p2 == p) |
|
+ { |
|
+ _asn1_set_right (p5, p->down); |
|
+ _asn1_set_down (p, p5); |
|
+ } |
|
+ else |
|
+ { |
|
+ _asn1_set_right (p5, p2->right); |
|
+ _asn1_set_right (p2, p5); |
|
+ } |
|
+ p2 = p5; |
|
+ } |
|
+ p4 = p4->right; |
|
+ } |
|
+ move = DOWN; |
|
+ |
|
+ tries++; |
|
+ if (tries >= EXPAND_OBJECT_ID_MAX_RECURSION) |
|
+ return ASN1_RECURSION; |
|
+ |
|
+ continue; |
|
+ } |
|
+ } |
|
+ } |
|
+ move = DOWN; |
|
+ } |
|
+ else |
|
+ move = RIGHT; |
|
+ |
|
+ tries = 0; |
|
+ if (move == DOWN) |
|
+ { |
|
+ if (p->down) |
|
+ p = p->down; |
|
+ else |
|
+ move = RIGHT; |
|
+ } |
|
+ |
|
+ if (p == node) |
|
+ { |
|
+ move = UP; |
|
+ continue; |
|
+ } |
|
+ |
|
+ if (move == RIGHT) |
|
+ { |
|
+ if (p && p->right) |
|
+ p = p->right; |
|
+ else |
|
+ move = UP; |
|
+ } |
|
+ if (move == UP) |
|
+ p = _asn1_find_up (p); |
|
+ } |
|
+ |
|
+ /*******************************/ |
|
+ /* expand DEFAULT */ |
|
+ /*******************************/ |
|
+ p = node; |
|
+ move = DOWN; |
|
+ |
|
+ while (!((p == node) && (move == UP))) |
|
+ { |
|
+ if (move != UP) |
|
+ { |
|
+ if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) && |
|
+ (p->type & CONST_DEFAULT)) |
|
+ { |
|
+ p2 = p->down; |
|
+ if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT)) |
|
+ { |
|
+ _asn1_str_cpy (name2, sizeof (name2), name_root); |
|
+ _asn1_str_cat (name2, sizeof (name2), "."); |
|
+ if (p2->value) |
|
+ _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); |
|
+ p3 = asn1_find_node (node, name2); |
|
+ if (!p3 || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) |
|
+ || !(p3->type & CONST_ASSIGN)) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ p4 = p3->down; |
|
+ name2[0] = 0; |
|
+ while (p4) |
|
+ { |
|
+ if (type_field (p4->type) == ASN1_ETYPE_CONSTANT) |
|
+ { |
|
+ if (p4->value == NULL) |
|
+ return ASN1_VALUE_NOT_FOUND; |
|
+ |
|
+ if (name2[0]) |
|
+ _asn1_str_cat (name2, sizeof (name2), "."); |
|
+ _asn1_str_cat (name2, sizeof (name2), |
|
+ (char *) p4->value); |
|
+ } |
|
+ p4 = p4->right; |
|
+ } |
|
+ tlen = strlen (name2); |
|
+ if (tlen > 0) |
|
+ _asn1_set_value (p2, name2, tlen + 1); |
|
+ } |
|
+ } |
|
+ move = DOWN; |
|
+ } |
|
+ else |
|
+ move = RIGHT; |
|
+ |
|
+ if (move == DOWN) |
|
+ { |
|
+ if (p->down) |
|
+ p = p->down; |
|
+ else |
|
+ move = RIGHT; |
|
+ } |
|
+ |
|
+ if (p == node) |
|
+ { |
|
+ move = UP; |
|
+ continue; |
|
+ } |
|
+ |
|
+ if (move == RIGHT) |
|
+ { |
|
+ if (p && p->right) |
|
+ p = p->right; |
|
+ else |
|
+ move = UP; |
|
+ } |
|
+ if (move == UP) |
|
+ p = _asn1_find_up (p); |
|
+ } |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_type_set_config */ |
|
+/* Description: sets the CONST_SET and CONST_NOT_USED properties */ |
|
+/* in the fields of the SET elements. */ |
|
+/* Parameters: */ |
|
+/* node: root of an ASN1 element. */ |
|
+/* Return: */ |
|
+/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ |
|
+/* otherwise ASN1_SUCCESS */ |
|
+/******************************************************************/ |
|
+int |
|
+_asn1_type_set_config (asn1_node node) |
|
+{ |
|
+ asn1_node p, p2; |
|
+ int move; |
|
+ |
|
+ if (node == NULL) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ p = node; |
|
+ move = DOWN; |
|
+ |
|
+ while (!((p == node) && (move == UP))) |
|
+ { |
|
+ if (move != UP) |
|
+ { |
|
+ if (type_field (p->type) == ASN1_ETYPE_SET) |
|
+ { |
|
+ p2 = p->down; |
|
+ while (p2) |
|
+ { |
|
+ if (type_field (p2->type) != ASN1_ETYPE_TAG) |
|
+ p2->type |= CONST_SET | CONST_NOT_USED; |
|
+ p2 = p2->right; |
|
+ } |
|
+ } |
|
+ move = DOWN; |
|
+ } |
|
+ else |
|
+ move = RIGHT; |
|
+ |
|
+ if (move == DOWN) |
|
+ { |
|
+ if (p->down) |
|
+ p = p->down; |
|
+ else |
|
+ move = RIGHT; |
|
+ } |
|
+ |
|
+ if (p == node) |
|
+ { |
|
+ move = UP; |
|
+ continue; |
|
+ } |
|
+ |
|
+ if (move == RIGHT) |
|
+ { |
|
+ if (p && p->right) |
|
+ p = p->right; |
|
+ else |
|
+ move = UP; |
|
+ } |
|
+ if (move == UP) |
|
+ p = _asn1_find_up (p); |
|
+ } |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_check_identifier */ |
|
+/* Description: checks the definitions of all the identifiers */ |
|
+/* and the first element of an OBJECT_ID (e.g. {pkix 0 4}). */ |
|
+/* The _asn1_identifierMissing global variable is filled if */ |
|
+/* necessary. */ |
|
+/* Parameters: */ |
|
+/* node: root of an ASN1 element. */ |
|
+/* Return: */ |
|
+/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ |
|
+/* ASN1_IDENTIFIER_NOT_FOUND if an identifier is not defined, */ |
|
+/* otherwise ASN1_SUCCESS */ |
|
+/******************************************************************/ |
|
+int |
|
+_asn1_check_identifier (asn1_node_const node) |
|
+{ |
|
+ asn1_node_const p, p2; |
|
+ char name2[ASN1_MAX_NAME_SIZE * 2 + 2]; |
|
+ |
|
+ if (node == NULL) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ p = node; |
|
+ while (p) |
|
+ { |
|
+ if (p->value && type_field (p->type) == ASN1_ETYPE_IDENTIFIER) |
|
+ { |
|
+ _asn1_str_cpy (name2, sizeof (name2), node->name); |
|
+ _asn1_str_cat (name2, sizeof (name2), "."); |
|
+ _asn1_str_cat (name2, sizeof (name2), (char *) p->value); |
|
+ p2 = asn1_find_node (node, name2); |
|
+ if (p2 == NULL) |
|
+ { |
|
+ if (p->value) |
|
+ _asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p->value); |
|
+ else |
|
+ _asn1_strcpy (_asn1_identifierMissing, "(null)"); |
|
+ return ASN1_IDENTIFIER_NOT_FOUND; |
|
+ } |
|
+ } |
|
+ else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) && |
|
+ (p->type & CONST_DEFAULT)) |
|
+ { |
|
+ p2 = p->down; |
|
+ if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT)) |
|
+ { |
|
+ _asn1_str_cpy (name2, sizeof (name2), node->name); |
|
+ if (p2->value) |
|
+ { |
|
+ _asn1_str_cat (name2, sizeof (name2), "."); |
|
+ _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); |
|
+ _asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p2->value); |
|
+ } |
|
+ else |
|
+ _asn1_strcpy (_asn1_identifierMissing, "(null)"); |
|
+ |
|
+ p2 = asn1_find_node (node, name2); |
|
+ if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID) || |
|
+ !(p2->type & CONST_ASSIGN)) |
|
+ return ASN1_IDENTIFIER_NOT_FOUND; |
|
+ else |
|
+ _asn1_identifierMissing[0] = 0; |
|
+ } |
|
+ } |
|
+ else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) && |
|
+ (p->type & CONST_ASSIGN)) |
|
+ { |
|
+ p2 = p->down; |
|
+ if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT)) |
|
+ { |
|
+ if (p2->value && !c_isdigit (p2->value[0])) |
|
+ { |
|
+ _asn1_str_cpy (name2, sizeof (name2), node->name); |
|
+ _asn1_str_cat (name2, sizeof (name2), "."); |
|
+ _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); |
|
+ _asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p2->value); |
|
+ |
|
+ p2 = asn1_find_node (node, name2); |
|
+ if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID) |
|
+ || !(p2->type & CONST_ASSIGN)) |
|
+ return ASN1_IDENTIFIER_NOT_FOUND; |
|
+ else |
|
+ _asn1_identifierMissing[0] = 0; |
|
+ } |
|
+ } |
|
+ } |
|
+ |
|
+ if (p->down) |
|
+ { |
|
+ p = p->down; |
|
+ } |
|
+ else if (p->right) |
|
+ p = p->right; |
|
+ else |
|
+ { |
|
+ while (p) |
|
+ { |
|
+ p = _asn1_find_up (p); |
|
+ if (p == node) |
|
+ { |
|
+ p = NULL; |
|
+ break; |
|
+ } |
|
+ if (p && p->right) |
|
+ { |
|
+ p = p->right; |
|
+ break; |
|
+ } |
|
+ } |
|
+ } |
|
+ } |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_set_default_tag */ |
|
+/* Description: sets the default IMPLICIT or EXPLICIT property in */ |
|
+/* the tagged elements that don't have this declaration. */ |
|
+/* Parameters: */ |
|
+/* node: pointer to a DEFINITIONS element. */ |
|
+/* Return: */ |
|
+/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL or not a pointer to */ |
|
+/* a DEFINITIONS element, */ |
|
+/* otherwise ASN1_SUCCESS */ |
|
+/******************************************************************/ |
|
+int |
|
+_asn1_set_default_tag (asn1_node node) |
|
+{ |
|
+ asn1_node p; |
|
+ |
|
+ if ((node == NULL) || (type_field (node->type) != ASN1_ETYPE_DEFINITIONS)) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ p = node; |
|
+ while (p) |
|
+ { |
|
+ if ((type_field (p->type) == ASN1_ETYPE_TAG) && |
|
+ !(p->type & CONST_EXPLICIT) && !(p->type & CONST_IMPLICIT)) |
|
+ { |
|
+ if (node->type & CONST_EXPLICIT) |
|
+ p->type |= CONST_EXPLICIT; |
|
+ else |
|
+ p->type |= CONST_IMPLICIT; |
|
+ } |
|
+ |
|
+ if (p->down) |
|
+ { |
|
+ p = p->down; |
|
+ } |
|
+ else if (p->right) |
|
+ p = p->right; |
|
+ else |
|
+ { |
|
+ while (1) |
|
+ { |
|
+ p = _asn1_find_up (p); |
|
+ if (p == node) |
|
+ { |
|
+ p = NULL; |
|
+ break; |
|
+ } |
|
+ if (p && p->right) |
|
+ { |
|
+ p = p->right; |
|
+ break; |
|
+ } |
|
+ } |
|
+ } |
|
+ } |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
diff --git a/grub-core/lib/libtasn1/lib/structure.c b/grub-core/lib/libtasn1/lib/structure.c |
|
new file mode 100644 |
|
index 00000000000..8189c56a4c9 |
|
--- /dev/null |
|
+++ b/grub-core/lib/libtasn1/lib/structure.c |
|
@@ -0,0 +1,1220 @@ |
|
+/* |
|
+ * Copyright (C) 2002-2014 Free Software Foundation, Inc. |
|
+ * |
|
+ * This file is part of LIBTASN1. |
|
+ * |
|
+ * The LIBTASN1 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 Street, Fifth Floor, Boston, MA |
|
+ * 02110-1301, USA |
|
+ */ |
|
+ |
|
+ |
|
+/*****************************************************/ |
|
+/* File: structure.c */ |
|
+/* Description: Functions to create and delete an */ |
|
+/* ASN1 tree. */ |
|
+/*****************************************************/ |
|
+ |
|
+ |
|
+#include <int.h> |
|
+#include <structure.h> |
|
+#include "parser_aux.h" |
|
+#include <gstr.h> |
|
+ |
|
+ |
|
+extern char _asn1_identifierMissing[]; |
|
+ |
|
+ |
|
+/******************************************************/ |
|
+/* Function : _asn1_add_single_node */ |
|
+/* Description: creates a new NODE_ASN element. */ |
|
+/* Parameters: */ |
|
+/* type: type of the new element (see ASN1_ETYPE_ */ |
|
+/* and CONST_ constants). */ |
|
+/* Return: pointer to the new element. */ |
|
+/******************************************************/ |
|
+asn1_node |
|
+_asn1_add_single_node (unsigned int type) |
|
+{ |
|
+ asn1_node punt; |
|
+ |
|
+ punt = calloc (1, sizeof (struct asn1_node_st)); |
|
+ if (punt == NULL) |
|
+ return NULL; |
|
+ |
|
+ punt->type = type; |
|
+ |
|
+ return punt; |
|
+} |
|
+ |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_find_left */ |
|
+/* Description: returns the NODE_ASN element with RIGHT field that*/ |
|
+/* points the element NODE. */ |
|
+/* Parameters: */ |
|
+/* node: NODE_ASN element pointer. */ |
|
+/* Return: NULL if not found. */ |
|
+/******************************************************************/ |
|
+asn1_node |
|
+_asn1_find_left (asn1_node_const node) |
|
+{ |
|
+ if ((node == NULL) || (node->left == NULL) || (node->left->down == node)) |
|
+ return NULL; |
|
+ |
|
+ return node->left; |
|
+} |
|
+ |
|
+ |
|
+int |
|
+_asn1_create_static_structure (asn1_node_const pointer, char *output_file_name, |
|
+ char *vector_name) |
|
+{ |
|
+ FILE *file; |
|
+ asn1_node_const p; |
|
+ unsigned long t; |
|
+ |
|
+ file = fopen (output_file_name, "w"); |
|
+ |
|
+ if (file == NULL) |
|
+ return ASN1_FILE_NOT_FOUND; |
|
+ |
|
+ fprintf (file, "#if HAVE_CONFIG_H\n"); |
|
+ fprintf (file, "# include \"config.h\"\n"); |
|
+ fprintf (file, "#endif\n\n"); |
|
+ |
|
+ fprintf (file, "#include <libtasn1.h>\n\n"); |
|
+ |
|
+ fprintf (file, "const asn1_static_node %s[] = {\n", vector_name); |
|
+ |
|
+ p = pointer; |
|
+ |
|
+ while (p) |
|
+ { |
|
+ fprintf (file, " { "); |
|
+ |
|
+ if (p->name[0] != 0) |
|
+ fprintf (file, "\"%s\", ", p->name); |
|
+ else |
|
+ fprintf (file, "NULL, "); |
|
+ |
|
+ t = p->type; |
|
+ if (p->down) |
|
+ t |= CONST_DOWN; |
|
+ if (p->right) |
|
+ t |= CONST_RIGHT; |
|
+ |
|
+ fprintf (file, "%lu, ", t); |
|
+ |
|
+ if (p->value) |
|
+ fprintf (file, "\"%s\"},\n", p->value); |
|
+ else |
|
+ fprintf (file, "NULL },\n"); |
|
+ |
|
+ if (p->down) |
|
+ { |
|
+ p = p->down; |
|
+ } |
|
+ else if (p->right) |
|
+ { |
|
+ p = p->right; |
|
+ } |
|
+ else |
|
+ { |
|
+ while (1) |
|
+ { |
|
+ p = _asn1_find_up (p); |
|
+ if (p == pointer) |
|
+ { |
|
+ p = NULL; |
|
+ break; |
|
+ } |
|
+ if (p->right) |
|
+ { |
|
+ p = p->right; |
|
+ break; |
|
+ } |
|
+ } |
|
+ } |
|
+ } |
|
+ |
|
+ fprintf (file, " { NULL, 0, NULL }\n};\n"); |
|
+ |
|
+ fclose (file); |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+ |
|
+/** |
|
+ * asn1_array2tree: |
|
+ * @array: specify the array that contains ASN.1 declarations |
|
+ * @definitions: return the pointer to the structure created by |
|
+ * *ARRAY ASN.1 declarations |
|
+ * @errorDescription: return the error description. |
|
+ * |
|
+ * Creates the structures needed to manage the ASN.1 definitions. |
|
+ * @array is a vector created by asn1_parser2array(). |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if structure was created correctly, |
|
+ * %ASN1_ELEMENT_NOT_EMPTY if *@definitions not NULL, |
|
+ * %ASN1_IDENTIFIER_NOT_FOUND if in the file there is an identifier |
|
+ * that is not defined (see @errorDescription for more information), |
|
+ * %ASN1_ARRAY_ERROR if the array pointed by @array is wrong. |
|
+ **/ |
|
+int |
|
+asn1_array2tree (const asn1_static_node * array, asn1_node * definitions, |
|
+ char *errorDescription) |
|
+{ |
|
+ asn1_node p, p_last = NULL; |
|
+ unsigned long k; |
|
+ int move; |
|
+ int result; |
|
+ unsigned int type; |
|
+ list_type *e_list = NULL; |
|
+ |
|
+ if (errorDescription) |
|
+ errorDescription[0] = 0; |
|
+ |
|
+ if (*definitions != NULL) |
|
+ return ASN1_ELEMENT_NOT_EMPTY; |
|
+ |
|
+ move = UP; |
|
+ |
|
+ for (k = 0; array[k].value || array[k].type || array[k].name; k++) |
|
+ { |
|
+ type = convert_old_type (array[k].type); |
|
+ |
|
+ p = _asn1_add_static_node (&e_list, type & (~CONST_DOWN)); |
|
+ if (array[k].name) |
|
+ _asn1_set_name (p, array[k].name); |
|
+ if (array[k].value) |
|
+ _asn1_set_value (p, array[k].value, strlen (array[k].value) + 1); |
|
+ |
|
+ if (*definitions == NULL) |
|
+ *definitions = p; |
|
+ |
|
+ if (move == DOWN) |
|
+ { |
|
+ if (p_last && p_last->down) |
|
+ _asn1_delete_structure (e_list, &p_last->down, 0); |
|
+ _asn1_set_down (p_last, p); |
|
+ } |
|
+ else if (move == RIGHT) |
|
+ { |
|
+ if (p_last && p_last->right) |
|
+ _asn1_delete_structure (e_list, &p_last->right, 0); |
|
+ _asn1_set_right (p_last, p); |
|
+ } |
|
+ |
|
+ p_last = p; |
|
+ |
|
+ if (type & CONST_DOWN) |
|
+ move = DOWN; |
|
+ else if (type & CONST_RIGHT) |
|
+ move = RIGHT; |
|
+ else |
|
+ { |
|
+ while (p_last != *definitions) |
|
+ { |
|
+ p_last = _asn1_find_up (p_last); |
|
+ |
|
+ if (p_last == NULL) |
|
+ break; |
|
+ |
|
+ if (p_last->type & CONST_RIGHT) |
|
+ { |
|
+ p_last->type &= ~CONST_RIGHT; |
|
+ move = RIGHT; |
|
+ break; |
|
+ } |
|
+ } /* while */ |
|
+ } |
|
+ } /* while */ |
|
+ |
|
+ if (p_last == *definitions) |
|
+ { |
|
+ result = _asn1_check_identifier (*definitions); |
|
+ if (result == ASN1_SUCCESS) |
|
+ { |
|
+ _asn1_change_integer_value (*definitions); |
|
+ result = _asn1_expand_object_id (&e_list, *definitions); |
|
+ } |
|
+ } |
|
+ else |
|
+ { |
|
+ result = ASN1_ARRAY_ERROR; |
|
+ } |
|
+ |
|
+ if (errorDescription != NULL) |
|
+ { |
|
+ if (result == ASN1_IDENTIFIER_NOT_FOUND) |
|
+ { |
|
+ Estrcpy (errorDescription, ":: identifier '"); |
|
+ Estrcat (errorDescription, _asn1_identifierMissing); |
|
+ Estrcat (errorDescription, "' not found"); |
|
+ } |
|
+ else |
|
+ errorDescription[0] = 0; |
|
+ } |
|
+ |
|
+ if (result != ASN1_SUCCESS) |
|
+ { |
|
+ _asn1_delete_list_and_nodes (e_list); |
|
+ *definitions = NULL; |
|
+ } |
|
+ else |
|
+ _asn1_delete_list (e_list); |
|
+ |
|
+ return result; |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_delete_structure: |
|
+ * @structure: pointer to the structure that you want to delete. |
|
+ * |
|
+ * Deletes the structure *@structure. At the end, *@structure is set |
|
+ * to NULL. |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if |
|
+ * *@structure was NULL. |
|
+ **/ |
|
+int |
|
+asn1_delete_structure (asn1_node * structure) |
|
+{ |
|
+ return _asn1_delete_structure (NULL, structure, 0); |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_delete_structure2: |
|
+ * @structure: pointer to the structure that you want to delete. |
|
+ * @flags: additional flags (see %ASN1_DELETE_FLAG) |
|
+ * |
|
+ * Deletes the structure *@structure. At the end, *@structure is set |
|
+ * to NULL. |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if |
|
+ * *@structure was NULL. |
|
+ **/ |
|
+int |
|
+asn1_delete_structure2 (asn1_node * structure, unsigned int flags) |
|
+{ |
|
+ return _asn1_delete_structure (NULL, structure, flags); |
|
+} |
|
+ |
|
+int |
|
+_asn1_delete_structure (list_type *e_list, asn1_node * structure, unsigned int flags) |
|
+{ |
|
+ asn1_node p, p2, p3; |
|
+ |
|
+ if (*structure == NULL) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ p = *structure; |
|
+ while (p) |
|
+ { |
|
+ if (p->down) |
|
+ { |
|
+ p = p->down; |
|
+ } |
|
+ else |
|
+ { /* no down */ |
|
+ p2 = p->right; |
|
+ if (p != *structure) |
|
+ { |
|
+ p3 = _asn1_find_up (p); |
|
+ _asn1_set_down (p3, p2); |
|
+ if (e_list) |
|
+ _asn1_delete_node_from_list (e_list, p); |
|
+ _asn1_remove_node (p, flags); |
|
+ p = p3; |
|
+ } |
|
+ else |
|
+ { /* p==root */ |
|
+ p3 = _asn1_find_left (p); |
|
+ if (!p3) |
|
+ { |
|
+ p3 = _asn1_find_up (p); |
|
+ if (p3) |
|
+ _asn1_set_down (p3, p2); |
|
+ else |
|
+ { |
|
+ if (p->right) |
|
+ p->right->left = NULL; |
|
+ } |
|
+ } |
|
+ else |
|
+ _asn1_set_right (p3, p2); |
|
+ if (e_list) |
|
+ _asn1_delete_node_from_list (e_list, p); |
|
+ _asn1_remove_node (p, flags); |
|
+ p = NULL; |
|
+ } |
|
+ } |
|
+ } |
|
+ |
|
+ *structure = NULL; |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+ |
|
+/** |
|
+ * asn1_delete_element: |
|
+ * @structure: pointer to the structure that contains the element you |
|
+ * want to delete. |
|
+ * @element_name: element's name you want to delete. |
|
+ * |
|
+ * Deletes the element named *@element_name inside *@structure. |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if |
|
+ * the @element_name was not found. |
|
+ **/ |
|
+int |
|
+asn1_delete_element (asn1_node structure, const char *element_name) |
|
+{ |
|
+ asn1_node p2, p3, source_node; |
|
+ |
|
+ source_node = asn1_find_node (structure, element_name); |
|
+ |
|
+ if (source_node == NULL) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ p2 = source_node->right; |
|
+ p3 = _asn1_find_left (source_node); |
|
+ if (!p3) |
|
+ { |
|
+ p3 = _asn1_find_up (source_node); |
|
+ if (p3) |
|
+ _asn1_set_down (p3, p2); |
|
+ else if (source_node->right) |
|
+ source_node->right->left = NULL; |
|
+ } |
|
+ else |
|
+ _asn1_set_right (p3, p2); |
|
+ |
|
+ return asn1_delete_structure (&source_node); |
|
+} |
|
+ |
|
+#ifndef __clang_analyzer__ |
|
+asn1_node |
|
+_asn1_copy_structure3 (asn1_node_const source_node) |
|
+{ |
|
+ asn1_node_const p_s; |
|
+ asn1_node dest_node, p_d, p_d_prev; |
|
+ int move; |
|
+ |
|
+ if (source_node == NULL) |
|
+ return NULL; |
|
+ |
|
+ dest_node = _asn1_add_single_node (source_node->type); |
|
+ |
|
+ p_s = source_node; |
|
+ p_d = dest_node; |
|
+ |
|
+ move = DOWN; |
|
+ |
|
+ do |
|
+ { |
|
+ if (move != UP) |
|
+ { |
|
+ if (p_s->name[0] != 0) |
|
+ _asn1_cpy_name (p_d, p_s); |
|
+ if (p_s->value) |
|
+ _asn1_set_value (p_d, p_s->value, p_s->value_len); |
|
+ if (p_s->down) |
|
+ { |
|
+ p_s = p_s->down; |
|
+ p_d_prev = p_d; |
|
+ p_d = _asn1_add_single_node (p_s->type); |
|
+ _asn1_set_down (p_d_prev, p_d); |
|
+ continue; |
|
+ } |
|
+ p_d->start = p_s->start; |
|
+ p_d->end = p_s->end; |
|
+ } |
|
+ |
|
+ if (p_s == source_node) |
|
+ break; |
|
+ |
|
+ if (p_s->right) |
|
+ { |
|
+ move = RIGHT; |
|
+ p_s = p_s->right; |
|
+ p_d_prev = p_d; |
|
+ p_d = _asn1_add_single_node (p_s->type); |
|
+ _asn1_set_right (p_d_prev, p_d); |
|
+ } |
|
+ else |
|
+ { |
|
+ move = UP; |
|
+ p_s = _asn1_find_up (p_s); |
|
+ p_d = _asn1_find_up (p_d); |
|
+ } |
|
+ } |
|
+ while (p_s != source_node); |
|
+ return dest_node; |
|
+} |
|
+#else |
|
+ |
|
+/* Non-production code */ |
|
+asn1_node |
|
+_asn1_copy_structure3 (asn1_node_const source_node) |
|
+{ |
|
+ return NULL; |
|
+} |
|
+#endif /* __clang_analyzer__ */ |
|
+ |
|
+ |
|
+static asn1_node |
|
+_asn1_copy_structure2 (asn1_node_const root, const char *source_name) |
|
+{ |
|
+ asn1_node source_node; |
|
+ |
|
+ source_node = asn1_find_node (root, source_name); |
|
+ |
|
+ return _asn1_copy_structure3 (source_node); |
|
+ |
|
+} |
|
+ |
|
+ |
|
+static int |
|
+_asn1_type_choice_config (asn1_node node) |
|
+{ |
|
+ asn1_node p, p2, p3, p4; |
|
+ int move, tlen; |
|
+ |
|
+ if (node == NULL) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ p = node; |
|
+ move = DOWN; |
|
+ |
|
+ while (!((p == node) && (move == UP))) |
|
+ { |
|
+ if (move != UP) |
|
+ { |
|
+ if ((type_field (p->type) == ASN1_ETYPE_CHOICE) |
|
+ && (p->type & CONST_TAG)) |
|
+ { |
|
+ p2 = p->down; |
|
+ while (p2) |
|
+ { |
|
+ if (type_field (p2->type) != ASN1_ETYPE_TAG) |
|
+ { |
|
+ p2->type |= CONST_TAG; |
|
+ p3 = _asn1_find_left (p2); |
|
+ while (p3) |
|
+ { |
|
+ if (type_field (p3->type) == ASN1_ETYPE_TAG) |
|
+ { |
|
+ p4 = _asn1_add_single_node (p3->type); |
|
+ tlen = _asn1_strlen (p3->value); |
|
+ if (tlen > 0) |
|
+ _asn1_set_value (p4, p3->value, tlen + 1); |
|
+ _asn1_set_right (p4, p2->down); |
|
+ _asn1_set_down (p2, p4); |
|
+ } |
|
+ p3 = _asn1_find_left (p3); |
|
+ } |
|
+ } |
|
+ p2 = p2->right; |
|
+ } |
|
+ p->type &= ~(CONST_TAG); |
|
+ p2 = p->down; |
|
+ while (p2) |
|
+ { |
|
+ p3 = p2->right; |
|
+ if (type_field (p2->type) == ASN1_ETYPE_TAG) |
|
+ asn1_delete_structure (&p2); |
|
+ p2 = p3; |
|
+ } |
|
+ } |
|
+ move = DOWN; |
|
+ } |
|
+ else |
|
+ move = RIGHT; |
|
+ |
|
+ if (move == DOWN) |
|
+ { |
|
+ if (p->down) |
|
+ p = p->down; |
|
+ else |
|
+ move = RIGHT; |
|
+ } |
|
+ |
|
+ if (p == node) |
|
+ { |
|
+ move = UP; |
|
+ continue; |
|
+ } |
|
+ |
|
+ if (move == RIGHT) |
|
+ { |
|
+ if (p->right) |
|
+ p = p->right; |
|
+ else |
|
+ move = UP; |
|
+ } |
|
+ if (move == UP) |
|
+ p = _asn1_find_up (p); |
|
+ } |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+ |
|
+static int |
|
+_asn1_expand_identifier (asn1_node * node, asn1_node_const root) |
|
+{ |
|
+ asn1_node p, p2, p3; |
|
+ char name2[ASN1_MAX_NAME_SIZE + 2]; |
|
+ int move; |
|
+ |
|
+ if (node == NULL) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ p = *node; |
|
+ move = DOWN; |
|
+ |
|
+ while (!((p == *node) && (move == UP))) |
|
+ { |
|
+ if (move != UP) |
|
+ { |
|
+ if (type_field (p->type) == ASN1_ETYPE_IDENTIFIER) |
|
+ { |
|
+ snprintf (name2, sizeof (name2), "%s.%s", root->name, p->value); |
|
+ p2 = _asn1_copy_structure2 (root, name2); |
|
+ if (p2 == NULL) |
|
+ { |
|
+ return ASN1_IDENTIFIER_NOT_FOUND; |
|
+ } |
|
+ _asn1_cpy_name (p2, p); |
|
+ p2->right = p->right; |
|
+ p2->left = p->left; |
|
+ if (p->right) |
|
+ p->right->left = p2; |
|
+ p3 = p->down; |
|
+ if (p3) |
|
+ { |
|
+ while (p3->right) |
|
+ p3 = p3->right; |
|
+ _asn1_set_right (p3, p2->down); |
|
+ _asn1_set_down (p2, p->down); |
|
+ } |
|
+ |
|
+ p3 = _asn1_find_left (p); |
|
+ if (p3) |
|
+ _asn1_set_right (p3, p2); |
|
+ else |
|
+ { |
|
+ p3 = _asn1_find_up (p); |
|
+ if (p3) |
|
+ _asn1_set_down (p3, p2); |
|
+ else |
|
+ { |
|
+ p2->left = NULL; |
|
+ } |
|
+ } |
|
+ |
|
+ if (p->type & CONST_SIZE) |
|
+ p2->type |= CONST_SIZE; |
|
+ if (p->type & CONST_TAG) |
|
+ p2->type |= CONST_TAG; |
|
+ if (p->type & CONST_OPTION) |
|
+ p2->type |= CONST_OPTION; |
|
+ if (p->type & CONST_DEFAULT) |
|
+ p2->type |= CONST_DEFAULT; |
|
+ if (p->type & CONST_SET) |
|
+ p2->type |= CONST_SET; |
|
+ if (p->type & CONST_NOT_USED) |
|
+ p2->type |= CONST_NOT_USED; |
|
+ |
|
+ if (p == *node) |
|
+ *node = p2; |
|
+ _asn1_remove_node (p, 0); |
|
+ p = p2; |
|
+ move = DOWN; |
|
+ continue; |
|
+ } |
|
+ move = DOWN; |
|
+ } |
|
+ else |
|
+ move = RIGHT; |
|
+ |
|
+ if (move == DOWN) |
|
+ { |
|
+ if (p->down) |
|
+ p = p->down; |
|
+ else |
|
+ move = RIGHT; |
|
+ } |
|
+ |
|
+ if (p == *node) |
|
+ { |
|
+ move = UP; |
|
+ continue; |
|
+ } |
|
+ |
|
+ if (move == RIGHT) |
|
+ { |
|
+ if (p->right) |
|
+ p = p->right; |
|
+ else |
|
+ move = UP; |
|
+ } |
|
+ if (move == UP) |
|
+ p = _asn1_find_up (p); |
|
+ } |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+ |
|
+/** |
|
+ * asn1_create_element: |
|
+ * @definitions: pointer to the structure returned by "parser_asn1" function |
|
+ * @source_name: the name of the type of the new structure (must be |
|
+ * inside p_structure). |
|
+ * @element: pointer to the structure created. |
|
+ * |
|
+ * Creates a structure of type @source_name. Example using |
|
+ * "pkix.asn": |
|
+ * |
|
+ * rc = asn1_create_element(cert_def, "PKIX1.Certificate", certptr); |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if creation OK, %ASN1_ELEMENT_NOT_FOUND if |
|
+ * @source_name is not known. |
|
+ **/ |
|
+int |
|
+asn1_create_element (asn1_node_const definitions, const char *source_name, |
|
+ asn1_node * element) |
|
+{ |
|
+ asn1_node dest_node; |
|
+ int res; |
|
+ |
|
+ dest_node = _asn1_copy_structure2 (definitions, source_name); |
|
+ |
|
+ if (dest_node == NULL) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ _asn1_set_name (dest_node, ""); |
|
+ |
|
+ res = _asn1_expand_identifier (&dest_node, definitions); |
|
+ _asn1_type_choice_config (dest_node); |
|
+ |
|
+ *element = dest_node; |
|
+ |
|
+ return res; |
|
+} |
|
+ |
|
+ |
|
+/** |
|
+ * asn1_print_structure: |
|
+ * @out: pointer to the output file (e.g. stdout). |
|
+ * @structure: pointer to the structure that you want to visit. |
|
+ * @name: an element of the structure |
|
+ * @mode: specify how much of the structure to print, can be |
|
+ * %ASN1_PRINT_NAME, %ASN1_PRINT_NAME_TYPE, |
|
+ * %ASN1_PRINT_NAME_TYPE_VALUE, or %ASN1_PRINT_ALL. |
|
+ * |
|
+ * Prints on the @out file descriptor the structure's tree starting |
|
+ * from the @name element inside the structure @structure. |
|
+ **/ |
|
+void |
|
+asn1_print_structure (FILE * out, asn1_node_const structure, const char *name, |
|
+ int mode) |
|
+{ |
|
+ asn1_node_const p, root; |
|
+ int k, indent = 0, len, len2, len3; |
|
+ |
|
+ if (out == NULL) |
|
+ return; |
|
+ |
|
+ root = asn1_find_node (structure, name); |
|
+ |
|
+ if (root == NULL) |
|
+ return; |
|
+ |
|
+ p = root; |
|
+ while (p) |
|
+ { |
|
+ if (mode == ASN1_PRINT_ALL) |
|
+ { |
|
+ for (k = 0; k < indent; k++) |
|
+ fprintf (out, " "); |
|
+ fprintf (out, "name:"); |
|
+ if (p->name[0] != 0) |
|
+ fprintf (out, "%s ", p->name); |
|
+ else |
|
+ fprintf (out, "NULL "); |
|
+ } |
|
+ else |
|
+ { |
|
+ switch (type_field (p->type)) |
|
+ { |
|
+ case ASN1_ETYPE_CONSTANT: |
|
+ case ASN1_ETYPE_TAG: |
|
+ case ASN1_ETYPE_SIZE: |
|
+ break; |
|
+ default: |
|
+ for (k = 0; k < indent; k++) |
|
+ fprintf (out, " "); |
|
+ fprintf (out, "name:"); |
|
+ if (p->name[0] != 0) |
|
+ fprintf (out, "%s ", p->name); |
|
+ else |
|
+ fprintf (out, "NULL "); |
|
+ } |
|
+ } |
|
+ |
|
+ if (mode != ASN1_PRINT_NAME) |
|
+ { |
|
+ unsigned type = type_field (p->type); |
|
+ switch (type) |
|
+ { |
|
+ case ASN1_ETYPE_CONSTANT: |
|
+ if (mode == ASN1_PRINT_ALL) |
|
+ fprintf (out, "type:CONST"); |
|
+ break; |
|
+ case ASN1_ETYPE_TAG: |
|
+ if (mode == ASN1_PRINT_ALL) |
|
+ fprintf (out, "type:TAG"); |
|
+ break; |
|
+ case ASN1_ETYPE_SIZE: |
|
+ if (mode == ASN1_PRINT_ALL) |
|
+ fprintf (out, "type:SIZE"); |
|
+ break; |
|
+ case ASN1_ETYPE_DEFAULT: |
|
+ fprintf (out, "type:DEFAULT"); |
|
+ break; |
|
+ case ASN1_ETYPE_IDENTIFIER: |
|
+ fprintf (out, "type:IDENTIFIER"); |
|
+ break; |
|
+ case ASN1_ETYPE_ANY: |
|
+ fprintf (out, "type:ANY"); |
|
+ break; |
|
+ case ASN1_ETYPE_CHOICE: |
|
+ fprintf (out, "type:CHOICE"); |
|
+ break; |
|
+ case ASN1_ETYPE_DEFINITIONS: |
|
+ fprintf (out, "type:DEFINITIONS"); |
|
+ break; |
|
+ CASE_HANDLED_ETYPES: |
|
+ fprintf (out, "%s", _asn1_tags[type].desc); |
|
+ break; |
|
+ default: |
|
+ break; |
|
+ } |
|
+ } |
|
+ |
|
+ if ((mode == ASN1_PRINT_NAME_TYPE_VALUE) || (mode == ASN1_PRINT_ALL)) |
|
+ { |
|
+ switch (type_field (p->type)) |
|
+ { |
|
+ case ASN1_ETYPE_CONSTANT: |
|
+ if (mode == ASN1_PRINT_ALL) |
|
+ if (p->value) |
|
+ fprintf (out, " value:%s", p->value); |
|
+ break; |
|
+ case ASN1_ETYPE_TAG: |
|
+ if (mode == ASN1_PRINT_ALL) |
|
+ if (p->value) |
|
+ fprintf (out, " value:%s", p->value); |
|
+ break; |
|
+ case ASN1_ETYPE_SIZE: |
|
+ if (mode == ASN1_PRINT_ALL) |
|
+ if (p->value) |
|
+ fprintf (out, " value:%s", p->value); |
|
+ break; |
|
+ case ASN1_ETYPE_DEFAULT: |
|
+ if (p->value) |
|
+ fprintf (out, " value:%s", p->value); |
|
+ else if (p->type & CONST_TRUE) |
|
+ fprintf (out, " value:TRUE"); |
|
+ else if (p->type & CONST_FALSE) |
|
+ fprintf (out, " value:FALSE"); |
|
+ break; |
|
+ case ASN1_ETYPE_IDENTIFIER: |
|
+ if (p->value) |
|
+ fprintf (out, " value:%s", p->value); |
|
+ break; |
|
+ case ASN1_ETYPE_INTEGER: |
|
+ if (p->value) |
|
+ { |
|
+ len2 = -1; |
|
+ len = asn1_get_length_der (p->value, p->value_len, &len2); |
|
+ fprintf (out, " value:0x"); |
|
+ if (len > 0) |
|
+ for (k = 0; k < len; k++) |
|
+ fprintf (out, "%02x", (unsigned) (p->value)[k + len2]); |
|
+ } |
|
+ break; |
|
+ case ASN1_ETYPE_ENUMERATED: |
|
+ if (p->value) |
|
+ { |
|
+ len2 = -1; |
|
+ len = asn1_get_length_der (p->value, p->value_len, &len2); |
|
+ fprintf (out, " value:0x"); |
|
+ if (len > 0) |
|
+ for (k = 0; k < len; k++) |
|
+ fprintf (out, "%02x", (unsigned) (p->value)[k + len2]); |
|
+ } |
|
+ break; |
|
+ case ASN1_ETYPE_BOOLEAN: |
|
+ if (p->value) |
|
+ { |
|
+ if (p->value[0] == 'T') |
|
+ fprintf (out, " value:TRUE"); |
|
+ else if (p->value[0] == 'F') |
|
+ fprintf (out, " value:FALSE"); |
|
+ } |
|
+ break; |
|
+ case ASN1_ETYPE_BIT_STRING: |
|
+ if (p->value) |
|
+ { |
|
+ len2 = -1; |
|
+ len = asn1_get_length_der (p->value, p->value_len, &len2); |
|
+ if (len > 0) |
|
+ { |
|
+ fprintf (out, " value(%i):", |
|
+ (len - 1) * 8 - (p->value[len2])); |
|
+ for (k = 1; k < len; k++) |
|
+ fprintf (out, "%02x", (unsigned) (p->value)[k + len2]); |
|
+ } |
|
+ } |
|
+ break; |
|
+ case ASN1_ETYPE_GENERALIZED_TIME: |
|
+ case ASN1_ETYPE_UTC_TIME: |
|
+ if (p->value) |
|
+ { |
|
+ fprintf (out, " value:"); |
|
+ for (k = 0; k < p->value_len; k++) |
|
+ fprintf (out, "%c", (p->value)[k]); |
|
+ } |
|
+ break; |
|
+ case ASN1_ETYPE_GENERALSTRING: |
|
+ case ASN1_ETYPE_NUMERIC_STRING: |
|
+ case ASN1_ETYPE_IA5_STRING: |
|
+ case ASN1_ETYPE_TELETEX_STRING: |
|
+ case ASN1_ETYPE_PRINTABLE_STRING: |
|
+ case ASN1_ETYPE_UNIVERSAL_STRING: |
|
+ case ASN1_ETYPE_UTF8_STRING: |
|
+ case ASN1_ETYPE_VISIBLE_STRING: |
|
+ if (p->value) |
|
+ { |
|
+ len2 = -1; |
|
+ len = asn1_get_length_der (p->value, p->value_len, &len2); |
|
+ fprintf (out, " value:"); |
|
+ if (len > 0) |
|
+ for (k = 0; k < len; k++) |
|
+ fprintf (out, "%c", (p->value)[k + len2]); |
|
+ } |
|
+ break; |
|
+ case ASN1_ETYPE_BMP_STRING: |
|
+ case ASN1_ETYPE_OCTET_STRING: |
|
+ if (p->value) |
|
+ { |
|
+ len2 = -1; |
|
+ len = asn1_get_length_der (p->value, p->value_len, &len2); |
|
+ fprintf (out, " value:"); |
|
+ if (len > 0) |
|
+ for (k = 0; k < len; k++) |
|
+ fprintf (out, "%02x", (unsigned) (p->value)[k + len2]); |
|
+ } |
|
+ break; |
|
+ case ASN1_ETYPE_OBJECT_ID: |
|
+ if (p->value) |
|
+ fprintf (out, " value:%s", p->value); |
|
+ break; |
|
+ case ASN1_ETYPE_ANY: |
|
+ if (p->value) |
|
+ { |
|
+ len3 = -1; |
|
+ len2 = asn1_get_length_der (p->value, p->value_len, &len3); |
|
+ fprintf (out, " value:"); |
|
+ if (len2 > 0) |
|
+ for (k = 0; k < len2; k++) |
|
+ fprintf (out, "%02x", (unsigned) (p->value)[k + len3]); |
|
+ } |
|
+ break; |
|
+ case ASN1_ETYPE_SET: |
|
+ case ASN1_ETYPE_SET_OF: |
|
+ case ASN1_ETYPE_CHOICE: |
|
+ case ASN1_ETYPE_DEFINITIONS: |
|
+ case ASN1_ETYPE_SEQUENCE_OF: |
|
+ case ASN1_ETYPE_SEQUENCE: |
|
+ case ASN1_ETYPE_NULL: |
|
+ break; |
|
+ default: |
|
+ break; |
|
+ } |
|
+ } |
|
+ |
|
+ if (mode == ASN1_PRINT_ALL) |
|
+ { |
|
+ if (p->type & 0x1FFFFF00) |
|
+ { |
|
+ fprintf (out, " attr:"); |
|
+ if (p->type & CONST_UNIVERSAL) |
|
+ fprintf (out, "UNIVERSAL,"); |
|
+ if (p->type & CONST_PRIVATE) |
|
+ fprintf (out, "PRIVATE,"); |
|
+ if (p->type & CONST_APPLICATION) |
|
+ fprintf (out, "APPLICATION,"); |
|
+ if (p->type & CONST_EXPLICIT) |
|
+ fprintf (out, "EXPLICIT,"); |
|
+ if (p->type & CONST_IMPLICIT) |
|
+ fprintf (out, "IMPLICIT,"); |
|
+ if (p->type & CONST_TAG) |
|
+ fprintf (out, "TAG,"); |
|
+ if (p->type & CONST_DEFAULT) |
|
+ fprintf (out, "DEFAULT,"); |
|
+ if (p->type & CONST_TRUE) |
|
+ fprintf (out, "TRUE,"); |
|
+ if (p->type & CONST_FALSE) |
|
+ fprintf (out, "FALSE,"); |
|
+ if (p->type & CONST_LIST) |
|
+ fprintf (out, "LIST,"); |
|
+ if (p->type & CONST_MIN_MAX) |
|
+ fprintf (out, "MIN_MAX,"); |
|
+ if (p->type & CONST_OPTION) |
|
+ fprintf (out, "OPTION,"); |
|
+ if (p->type & CONST_1_PARAM) |
|
+ fprintf (out, "1_PARAM,"); |
|
+ if (p->type & CONST_SIZE) |
|
+ fprintf (out, "SIZE,"); |
|
+ if (p->type & CONST_DEFINED_BY) |
|
+ fprintf (out, "DEF_BY,"); |
|
+ if (p->type & CONST_GENERALIZED) |
|
+ fprintf (out, "GENERALIZED,"); |
|
+ if (p->type & CONST_UTC) |
|
+ fprintf (out, "UTC,"); |
|
+ if (p->type & CONST_SET) |
|
+ fprintf (out, "SET,"); |
|
+ if (p->type & CONST_NOT_USED) |
|
+ fprintf (out, "NOT_USED,"); |
|
+ if (p->type & CONST_ASSIGN) |
|
+ fprintf (out, "ASSIGNMENT,"); |
|
+ } |
|
+ } |
|
+ |
|
+ if (mode == ASN1_PRINT_ALL) |
|
+ { |
|
+ fprintf (out, "\n"); |
|
+ } |
|
+ else |
|
+ { |
|
+ switch (type_field (p->type)) |
|
+ { |
|
+ case ASN1_ETYPE_CONSTANT: |
|
+ case ASN1_ETYPE_TAG: |
|
+ case ASN1_ETYPE_SIZE: |
|
+ break; |
|
+ default: |
|
+ fprintf (out, "\n"); |
|
+ } |
|
+ } |
|
+ |
|
+ if (p->down) |
|
+ { |
|
+ p = p->down; |
|
+ indent += 2; |
|
+ } |
|
+ else if (p == root) |
|
+ { |
|
+ p = NULL; |
|
+ break; |
|
+ } |
|
+ else if (p->right) |
|
+ p = p->right; |
|
+ else |
|
+ { |
|
+ while (1) |
|
+ { |
|
+ p = _asn1_find_up (p); |
|
+ if (p == root) |
|
+ { |
|
+ p = NULL; |
|
+ break; |
|
+ } |
|
+ indent -= 2; |
|
+ if (p->right) |
|
+ { |
|
+ p = p->right; |
|
+ break; |
|
+ } |
|
+ } |
|
+ } |
|
+ } |
|
+} |
|
+ |
|
+ |
|
+ |
|
+/** |
|
+ * asn1_number_of_elements: |
|
+ * @element: pointer to the root of an ASN1 structure. |
|
+ * @name: the name of a sub-structure of ROOT. |
|
+ * @num: pointer to an integer where the result will be stored |
|
+ * |
|
+ * Counts the number of elements of a sub-structure called NAME with |
|
+ * names equal to "?1","?2", ... |
|
+ * |
|
+ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if |
|
+ * @name is not known, %ASN1_GENERIC_ERROR if pointer @num is %NULL. |
|
+ **/ |
|
+int |
|
+asn1_number_of_elements (asn1_node_const element, const char *name, int *num) |
|
+{ |
|
+ asn1_node_const node, p; |
|
+ |
|
+ if (num == NULL) |
|
+ return ASN1_GENERIC_ERROR; |
|
+ |
|
+ *num = 0; |
|
+ |
|
+ node = asn1_find_node (element, name); |
|
+ if (node == NULL) |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ |
|
+ p = node->down; |
|
+ |
|
+ while (p) |
|
+ { |
|
+ if (p->name[0] == '?') |
|
+ (*num)++; |
|
+ p = p->right; |
|
+ } |
|
+ |
|
+ return ASN1_SUCCESS; |
|
+} |
|
+ |
|
+ |
|
+/** |
|
+ * asn1_find_structure_from_oid: |
|
+ * @definitions: ASN1 definitions |
|
+ * @oidValue: value of the OID to search (e.g. "1.2.3.4"). |
|
+ * |
|
+ * Search the structure that is defined just after an OID definition. |
|
+ * |
|
+ * Returns: %NULL when @oidValue not found, otherwise the pointer to a |
|
+ * constant string that contains the element name defined just after |
|
+ * the OID. |
|
+ **/ |
|
+const char * |
|
+asn1_find_structure_from_oid (asn1_node_const definitions, const char *oidValue) |
|
+{ |
|
+ char name[2 * ASN1_MAX_NAME_SIZE + 2]; |
|
+ char value[ASN1_MAX_NAME_SIZE]; |
|
+ asn1_node p; |
|
+ int len; |
|
+ int result; |
|
+ const char *definitionsName; |
|
+ |
|
+ if ((definitions == NULL) || (oidValue == NULL)) |
|
+ return NULL; /* ASN1_ELEMENT_NOT_FOUND; */ |
|
+ |
|
+ definitionsName = definitions->name; |
|
+ |
|
+ /* search the OBJECT_ID into definitions */ |
|
+ p = definitions->down; |
|
+ while (p) |
|
+ { |
|
+ if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) && |
|
+ (p->type & CONST_ASSIGN)) |
|
+ { |
|
+ snprintf(name, sizeof(name), "%s.%s", definitionsName, p->name); |
|
+ |
|
+ len = ASN1_MAX_NAME_SIZE; |
|
+ result = asn1_read_value (definitions, name, value, &len); |
|
+ |
|
+ if ((result == ASN1_SUCCESS) && (!strcmp (oidValue, value))) |
|
+ { |
|
+ p = p->right; |
|
+ if (p == NULL) /* reach the end of ASN1 definitions */ |
|
+ return NULL; /* ASN1_ELEMENT_NOT_FOUND; */ |
|
+ |
|
+ return p->name; |
|
+ } |
|
+ } |
|
+ p = p->right; |
|
+ } |
|
+ |
|
+ return NULL; /* ASN1_ELEMENT_NOT_FOUND; */ |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_copy_node: |
|
+ * @dst: Destination asn1 node. |
|
+ * @dst_name: Field name in destination node. |
|
+ * @src: Source asn1 node. |
|
+ * @src_name: Field name in source node. |
|
+ * |
|
+ * Create a deep copy of a asn1_node variable. That |
|
+ * function requires @dst to be expanded using asn1_create_element(). |
|
+ * |
|
+ * Returns: Return %ASN1_SUCCESS on success. |
|
+ **/ |
|
+int |
|
+asn1_copy_node (asn1_node dst, const char *dst_name, |
|
+ asn1_node_const src, const char *src_name) |
|
+{ |
|
+ int result; |
|
+ asn1_node dst_node; |
|
+ void *data = NULL; |
|
+ int size = 0; |
|
+ |
|
+ result = asn1_der_coding (src, src_name, NULL, &size, NULL); |
|
+ if (result != ASN1_MEM_ERROR) |
|
+ return result; |
|
+ |
|
+ data = malloc (size); |
|
+ if (data == NULL) |
|
+ return ASN1_MEM_ERROR; |
|
+ |
|
+ result = asn1_der_coding (src, src_name, data, &size, NULL); |
|
+ if (result != ASN1_SUCCESS) |
|
+ { |
|
+ free (data); |
|
+ return result; |
|
+ } |
|
+ |
|
+ dst_node = asn1_find_node (dst, dst_name); |
|
+ if (dst_node == NULL) |
|
+ { |
|
+ free (data); |
|
+ return ASN1_ELEMENT_NOT_FOUND; |
|
+ } |
|
+ |
|
+ result = asn1_der_decoding (&dst_node, data, size, NULL); |
|
+ |
|
+ free (data); |
|
+ |
|
+ return result; |
|
+} |
|
+ |
|
+/** |
|
+ * asn1_dup_node: |
|
+ * @src: Source asn1 node. |
|
+ * @src_name: Field name in source node. |
|
+ * |
|
+ * Create a deep copy of a asn1_node variable. This function |
|
+ * will return an exact copy of the provided structure. |
|
+ * |
|
+ * Returns: Return %NULL on failure. |
|
+ **/ |
|
+asn1_node |
|
+asn1_dup_node (asn1_node_const src, const char *src_name) |
|
+{ |
|
+ return _asn1_copy_structure2(src, src_name); |
|
+} |
|
diff --git a/grub-core/lib/libtasn1/lib/element.h b/grub-core/lib/libtasn1/lib/element.h |
|
new file mode 100644 |
|
index 00000000000..440a33f4bb1 |
|
--- /dev/null |
|
+++ b/grub-core/lib/libtasn1/lib/element.h |
|
@@ -0,0 +1,40 @@ |
|
+/* |
|
+ * Copyright (C) 2000-2014 Free Software Foundation, Inc. |
|
+ * |
|
+ * This file is part of LIBTASN1. |
|
+ * |
|
+ * The LIBTASN1 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 Street, Fifth Floor, Boston, MA |
|
+ * 02110-1301, USA |
|
+ */ |
|
+ |
|
+#ifndef _ELEMENT_H |
|
+#define _ELEMENT_H |
|
+ |
|
+ |
|
+struct node_tail_cache_st |
|
+{ |
|
+ asn1_node head; /* the first element of the sequence */ |
|
+ asn1_node tail; |
|
+}; |
|
+ |
|
+int _asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcached); |
|
+ |
|
+int _asn1_convert_integer (const unsigned char *value, |
|
+ unsigned char *value_out, |
|
+ int value_out_size, int *len); |
|
+ |
|
+void _asn1_hierarchical_name (asn1_node_const node, char *name, int name_size); |
|
+ |
|
+#endif |
|
diff --git a/grub-core/lib/libtasn1/lib/gstr.h b/grub-core/lib/libtasn1/lib/gstr.h |
|
new file mode 100644 |
|
index 00000000000..48229844ff3 |
|
--- /dev/null |
|
+++ b/grub-core/lib/libtasn1/lib/gstr.h |
|
@@ -0,0 +1,47 @@ |
|
+/* |
|
+ * Copyright (C) 2002-2014 Free Software Foundation, Inc. |
|
+ * |
|
+ * This file is part of LIBTASN1. |
|
+ * |
|
+ * The LIBTASN1 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 Street, Fifth Floor, Boston, MA |
|
+ * 02110-1301, USA |
|
+ */ |
|
+ |
|
+#ifndef GSTR_H |
|
+# define GSTR_H |
|
+ |
|
+unsigned int _asn1_str_cpy (char *dest, size_t dest_tot_size, |
|
+ const char *src); |
|
+void _asn1_str_cat (char *dest, size_t dest_tot_size, const char *src); |
|
+ |
|
+#define Estrcpy(x,y) _asn1_str_cpy(x,ASN1_MAX_ERROR_DESCRIPTION_SIZE,y) |
|
+#define Estrcat(x,y) _asn1_str_cat(x,ASN1_MAX_ERROR_DESCRIPTION_SIZE,y) |
|
+ |
|
+inline static |
|
+void safe_memset(void *data, int c, size_t size) |
|
+{ |
|
+ volatile unsigned volatile_zero = 0; |
|
+ volatile char *vdata = (volatile char*)data; |
|
+ |
|
+ /* This is based on a nice trick for safe memset, |
|
+ * sent by David Jacobson in the openssl-dev mailing list. |
|
+ */ |
|
+ |
|
+ if (size > 0) do { |
|
+ memset(data, c, size); |
|
+ } while(vdata[volatile_zero] != c); |
|
+} |
|
+ |
|
+#endif /* GSTR_H */ |
|
diff --git a/grub-core/lib/libtasn1/lib/int.h b/grub-core/lib/libtasn1/lib/int.h |
|
new file mode 100644 |
|
index 00000000000..ea1625786c1 |
|
--- /dev/null |
|
+++ b/grub-core/lib/libtasn1/lib/int.h |
|
@@ -0,0 +1,221 @@ |
|
+/* |
|
+ * Copyright (C) 2002-2014 Free Software Foundation, Inc. |
|
+ * |
|
+ * This file is part of LIBTASN1. |
|
+ * |
|
+ * The LIBTASN1 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 Street, Fifth Floor, Boston, MA |
|
+ * 02110-1301, USA |
|
+ */ |
|
+ |
|
+#ifndef INT_H |
|
+#define INT_H |
|
+ |
|
+#ifdef HAVE_CONFIG_H |
|
+#include <config.h> |
|
+#endif |
|
+ |
|
+#include <string.h> |
|
+#include <stdlib.h> |
|
+#include <stdio.h> |
|
+#include <stdint.h> |
|
+ |
|
+#ifdef HAVE_SYS_TYPES_H |
|
+#include <sys/types.h> |
|
+#endif |
|
+ |
|
+#include <libtasn1.h> |
|
+ |
|
+#define ASN1_SMALL_VALUE_SIZE 16 |
|
+ |
|
+/* This structure is also in libtasn1.h, but then contains less |
|
+ fields. You cannot make any modifications to these first fields |
|
+ without breaking ABI. */ |
|
+struct asn1_node_st |
|
+{ |
|
+ /* public fields: */ |
|
+ char name[ASN1_MAX_NAME_SIZE + 1]; /* Node name */ |
|
+ unsigned int name_hash; |
|
+ unsigned int type; /* Node type */ |
|
+ unsigned char *value; /* Node value */ |
|
+ int value_len; |
|
+ asn1_node down; /* Pointer to the son node */ |
|
+ asn1_node right; /* Pointer to the brother node */ |
|
+ asn1_node left; /* Pointer to the next list element */ |
|
+ /* private fields: */ |
|
+ unsigned char small_value[ASN1_SMALL_VALUE_SIZE]; /* For small values */ |
|
+ |
|
+ /* values used during decoding/coding */ |
|
+ int tmp_ival; |
|
+ unsigned start; /* the start of the DER sequence - if decoded */ |
|
+ unsigned end; /* the end of the DER sequence - if decoded */ |
|
+}; |
|
+ |
|
+typedef struct tag_and_class_st |
|
+{ |
|
+ unsigned tag; |
|
+ unsigned class; |
|
+ const char *desc; |
|
+} tag_and_class_st; |
|
+ |
|
+/* the types that are handled in _asn1_tags */ |
|
+#define CASE_HANDLED_ETYPES \ |
|
+ case ASN1_ETYPE_NULL: \ |
|
+ case ASN1_ETYPE_BOOLEAN: \ |
|
+ case ASN1_ETYPE_INTEGER: \ |
|
+ case ASN1_ETYPE_ENUMERATED: \ |
|
+ case ASN1_ETYPE_OBJECT_ID: \ |
|
+ case ASN1_ETYPE_OCTET_STRING: \ |
|
+ case ASN1_ETYPE_GENERALSTRING: \ |
|
+ case ASN1_ETYPE_NUMERIC_STRING: \ |
|
+ case ASN1_ETYPE_IA5_STRING: \ |
|
+ case ASN1_ETYPE_TELETEX_STRING: \ |
|
+ case ASN1_ETYPE_PRINTABLE_STRING: \ |
|
+ case ASN1_ETYPE_UNIVERSAL_STRING: \ |
|
+ case ASN1_ETYPE_BMP_STRING: \ |
|
+ case ASN1_ETYPE_UTF8_STRING: \ |
|
+ case ASN1_ETYPE_VISIBLE_STRING: \ |
|
+ case ASN1_ETYPE_BIT_STRING: \ |
|
+ case ASN1_ETYPE_SEQUENCE: \ |
|
+ case ASN1_ETYPE_SEQUENCE_OF: \ |
|
+ case ASN1_ETYPE_SET: \ |
|
+ case ASN1_ETYPE_UTC_TIME: \ |
|
+ case ASN1_ETYPE_GENERALIZED_TIME: \ |
|
+ case ASN1_ETYPE_SET_OF |
|
+ |
|
+#define ETYPE_TAG(etype) (_asn1_tags[etype].tag) |
|
+#define ETYPE_CLASS(etype) (_asn1_tags[etype].class) |
|
+#define ETYPE_OK(etype) (((etype) != ASN1_ETYPE_INVALID && \ |
|
+ (etype) <= _asn1_tags_size && \ |
|
+ _asn1_tags[(etype)].desc != NULL)?1:0) |
|
+ |
|
+#define ETYPE_IS_STRING(etype) ((etype == ASN1_ETYPE_GENERALSTRING || \ |
|
+ etype == ASN1_ETYPE_NUMERIC_STRING || etype == ASN1_ETYPE_IA5_STRING || \ |
|
+ etype == ASN1_ETYPE_TELETEX_STRING || etype == ASN1_ETYPE_PRINTABLE_STRING || \ |
|
+ etype == ASN1_ETYPE_UNIVERSAL_STRING || etype == ASN1_ETYPE_BMP_STRING || \ |
|
+ etype == ASN1_ETYPE_UTF8_STRING || etype == ASN1_ETYPE_VISIBLE_STRING || \ |
|
+ etype == ASN1_ETYPE_OCTET_STRING)?1:0) |
|
+ |
|
+extern unsigned int _asn1_tags_size; |
|
+extern const tag_and_class_st _asn1_tags[]; |
|
+ |
|
+#define _asn1_strlen(s) strlen((const char *) s) |
|
+#define _asn1_strtol(n,e,b) strtol((const char *) n, e, b) |
|
+#define _asn1_strtoul(n,e,b) strtoul((const char *) n, e, b) |
|
+#define _asn1_strcmp(a,b) strcmp((const char *)a, (const char *)b) |
|
+#define _asn1_strcpy(a,b) strcpy((char *)a, (const char *)b) |
|
+#define _asn1_strcat(a,b) strcat((char *)a, (const char *)b) |
|
+ |
|
+#if SIZEOF_UNSIGNED_LONG_INT == 8 |
|
+# define _asn1_strtou64(n,e,b) strtoul((const char *) n, e, b) |
|
+#else |
|
+# define _asn1_strtou64(n,e,b) strtoull((const char *) n, e, b) |
|
+#endif |
|
+ |
|
+#define MAX_LOG_SIZE 1024 /* maximum number of characters of a log message */ |
|
+ |
|
+/* Define used for visiting trees. */ |
|
+#define UP 1 |
|
+#define RIGHT 2 |
|
+#define DOWN 3 |
|
+ |
|
+/***********************************************************************/ |
|
+/* List of constants to better specify the type of typedef asn1_node_st. */ |
|
+/***********************************************************************/ |
|
+/* Used with TYPE_TAG */ |
|
+#define CONST_UNIVERSAL (1U<<8) |
|
+#define CONST_PRIVATE (1U<<9) |
|
+#define CONST_APPLICATION (1U<<10) |
|
+#define CONST_EXPLICIT (1U<<11) |
|
+#define CONST_IMPLICIT (1U<<12) |
|
+ |
|
+#define CONST_TAG (1U<<13) /* Used in ASN.1 assignement */ |
|
+#define CONST_OPTION (1U<<14) |
|
+#define CONST_DEFAULT (1U<<15) |
|
+#define CONST_TRUE (1U<<16) |
|
+#define CONST_FALSE (1U<<17) |
|
+ |
|
+#define CONST_LIST (1U<<18) /* Used with TYPE_INTEGER and TYPE_BIT_STRING */ |
|
+#define CONST_MIN_MAX (1U<<19) |
|
+ |
|
+#define CONST_1_PARAM (1U<<20) |
|
+ |
|
+#define CONST_SIZE (1U<<21) |
|
+ |
|
+#define CONST_DEFINED_BY (1U<<22) |
|
+ |
|
+/* Those two are deprecated and used for backwards compatibility */ |
|
+#define CONST_GENERALIZED (1U<<23) |
|
+#define CONST_UTC (1U<<24) |
|
+ |
|
+/* #define CONST_IMPORTS (1U<<25) */ |
|
+ |
|
+#define CONST_NOT_USED (1U<<26) |
|
+#define CONST_SET (1U<<27) |
|
+#define CONST_ASSIGN (1U<<28) |
|
+ |
|
+#define CONST_DOWN (1U<<29) |
|
+#define CONST_RIGHT (1U<<30) |
|
+ |
|
+ |
|
+#define ASN1_ETYPE_TIME 17 |
|
+/****************************************/ |
|
+/* Returns the first 8 bits. */ |
|
+/* Used with the field type of asn1_node_st */ |
|
+/****************************************/ |
|
+inline static unsigned int |
|
+type_field (unsigned int ntype) |
|
+{ |
|
+ return (ntype & 0xff); |
|
+} |
|
+ |
|
+/* To convert old types from a static structure */ |
|
+inline static unsigned int |
|
+convert_old_type (unsigned int ntype) |
|
+{ |
|
+ unsigned int type = ntype & 0xff; |
|
+ if (type == ASN1_ETYPE_TIME) |
|
+ { |
|
+ if (ntype & CONST_UTC) |
|
+ type = ASN1_ETYPE_UTC_TIME; |
|
+ else |
|
+ type = ASN1_ETYPE_GENERALIZED_TIME; |
|
+ |
|
+ ntype &= ~(CONST_UTC | CONST_GENERALIZED); |
|
+ ntype &= 0xffffff00; |
|
+ ntype |= type; |
|
+ |
|
+ return ntype; |
|
+ } |
|
+ else |
|
+ return ntype; |
|
+} |
|
+ |
|
+static inline |
|
+void *_asn1_realloc(void *ptr, size_t size) |
|
+{ |
|
+ void *ret; |
|
+ |
|
+ if (size == 0) |
|
+ return ptr; |
|
+ |
|
+ ret = realloc(ptr, size); |
|
+ if (ret == NULL) |
|
+ { |
|
+ free(ptr); |
|
+ } |
|
+ return ret; |
|
+} |
|
+ |
|
+#endif /* INT_H */ |
|
diff --git a/grub-core/lib/libtasn1/lib/parser_aux.h b/grub-core/lib/libtasn1/lib/parser_aux.h |
|
new file mode 100644 |
|
index 00000000000..598e684b355 |
|
--- /dev/null |
|
+++ b/grub-core/lib/libtasn1/lib/parser_aux.h |
|
@@ -0,0 +1,172 @@ |
|
+/* |
|
+ * Copyright (C) 2000-2014 Free Software Foundation, Inc. |
|
+ * |
|
+ * This file is part of LIBTASN1. |
|
+ * |
|
+ * The LIBTASN1 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 Street, Fifth Floor, Boston, MA |
|
+ * 02110-1301, USA |
|
+ */ |
|
+ |
|
+#ifndef _PARSER_AUX_H |
|
+#define _PARSER_AUX_H |
|
+ |
|
+/***********************************************/ |
|
+/* Type: list_type */ |
|
+/* Description: type used in the list during */ |
|
+/* the structure creation. */ |
|
+/***********************************************/ |
|
+typedef struct list_struct |
|
+{ |
|
+ asn1_node node; |
|
+ struct list_struct *next; |
|
+} list_type; |
|
+ |
|
+/***************************************/ |
|
+/* Functions used by ASN.1 parser */ |
|
+/***************************************/ |
|
+asn1_node _asn1_add_static_node (list_type **e_list, unsigned int type); |
|
+ |
|
+void _asn1_delete_list (list_type *e_list); |
|
+ |
|
+void _asn1_delete_list_and_nodes (list_type *e_list); |
|
+ |
|
+void _asn1_delete_node_from_list (list_type *list, asn1_node node); |
|
+ |
|
+asn1_node |
|
+_asn1_set_value (asn1_node node, const void *value, unsigned int len); |
|
+ |
|
+asn1_node _asn1_set_value_m (asn1_node node, void *value, unsigned int len); |
|
+ |
|
+asn1_node |
|
+_asn1_set_value_lv (asn1_node node, const void *value, unsigned int len); |
|
+ |
|
+asn1_node |
|
+_asn1_append_value (asn1_node node, const void *value, unsigned int len); |
|
+ |
|
+asn1_node _asn1_set_name (asn1_node node, const char *name); |
|
+ |
|
+asn1_node _asn1_cpy_name (asn1_node dst, asn1_node_const src); |
|
+ |
|
+asn1_node _asn1_set_right (asn1_node node, asn1_node right); |
|
+ |
|
+asn1_node _asn1_get_last_right (asn1_node_const node); |
|
+ |
|
+void _asn1_remove_node (asn1_node node, unsigned int flags); |
|
+ |
|
+/* Max 64-bit integer length is 20 chars + 1 for sign + 1 for null termination */ |
|
+#define LTOSTR_MAX_SIZE 22 |
|
+char *_asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE]); |
|
+ |
|
+asn1_node _asn1_find_up (asn1_node_const node); |
|
+ |
|
+int _asn1_change_integer_value (asn1_node node); |
|
+ |
|
+#define EXPAND_OBJECT_ID_MAX_RECURSION 16 |
|
+int _asn1_expand_object_id (list_type **list, asn1_node node); |
|
+ |
|
+int _asn1_type_set_config (asn1_node node); |
|
+ |
|
+int _asn1_check_identifier (asn1_node_const node); |
|
+ |
|
+int _asn1_set_default_tag (asn1_node node); |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_get_right */ |
|
+/* Description: returns the element pointed by the RIGHT field of */ |
|
+/* a NODE_ASN element. */ |
|
+/* Parameters: */ |
|
+/* node: NODE_ASN element pointer. */ |
|
+/* Return: field RIGHT of NODE. */ |
|
+/******************************************************************/ |
|
+inline static asn1_node |
|
+_asn1_get_right (asn1_node_const node) |
|
+{ |
|
+ if (node == NULL) |
|
+ return NULL; |
|
+ return node->right; |
|
+} |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_set_down */ |
|
+/* Description: sets the field DOWN in a NODE_ASN element. */ |
|
+/* Parameters: */ |
|
+/* node: element pointer. */ |
|
+/* down: pointer to a NODE_ASN element that you want be pointed */ |
|
+/* by NODE. */ |
|
+/* Return: pointer to *NODE. */ |
|
+/******************************************************************/ |
|
+inline static asn1_node |
|
+_asn1_set_down (asn1_node node, asn1_node down) |
|
+{ |
|
+ if (node == NULL) |
|
+ return node; |
|
+ node->down = down; |
|
+ if (down) |
|
+ down->left = node; |
|
+ return node; |
|
+} |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_get_down */ |
|
+/* Description: returns the element pointed by the DOWN field of */ |
|
+/* a NODE_ASN element. */ |
|
+/* Parameters: */ |
|
+/* node: NODE_ASN element pointer. */ |
|
+/* Return: field DOWN of NODE. */ |
|
+/******************************************************************/ |
|
+inline static asn1_node |
|
+_asn1_get_down (asn1_node_const node) |
|
+{ |
|
+ if (node == NULL) |
|
+ return NULL; |
|
+ return node->down; |
|
+} |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_get_name */ |
|
+/* Description: returns the name of a NODE_ASN element. */ |
|
+/* Parameters: */ |
|
+/* node: NODE_ASN element pointer. */ |
|
+/* Return: a null terminated string. */ |
|
+/******************************************************************/ |
|
+inline static char * |
|
+_asn1_get_name (asn1_node_const node) |
|
+{ |
|
+ if (node == NULL) |
|
+ return NULL; |
|
+ return (char *) node->name; |
|
+} |
|
+ |
|
+/******************************************************************/ |
|
+/* Function : _asn1_mod_type */ |
|
+/* Description: change the field TYPE of an NODE_ASN element. */ |
|
+/* The new value is the old one | (bitwise or) the */ |
|
+/* paramener VALUE. */ |
|
+/* Parameters: */ |
|
+/* node: NODE_ASN element pointer. */ |
|
+/* value: the integer value that must be or-ed with the current */ |
|
+/* value of field TYPE. */ |
|
+/* Return: NODE pointer. */ |
|
+/******************************************************************/ |
|
+inline static asn1_node |
|
+_asn1_mod_type (asn1_node node, unsigned int value) |
|
+{ |
|
+ if (node == NULL) |
|
+ return node; |
|
+ node->type |= value; |
|
+ return node; |
|
+} |
|
+ |
|
+#endif |
|
diff --git a/grub-core/lib/libtasn1/lib/structure.h b/grub-core/lib/libtasn1/lib/structure.h |
|
new file mode 100644 |
|
index 00000000000..99e685da07a |
|
--- /dev/null |
|
+++ b/grub-core/lib/libtasn1/lib/structure.h |
|
@@ -0,0 +1,45 @@ |
|
+/* |
|
+ * Copyright (C) 2002-2014 Free Software Foundation, Inc. |
|
+ * |
|
+ * This file is part of LIBTASN1. |
|
+ * |
|
+ * The LIBTASN1 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 Street, Fifth Floor, Boston, MA |
|
+ * 02110-1301, USA |
|
+ */ |
|
+ |
|
+/*************************************************/ |
|
+/* File: structure.h */ |
|
+/* Description: list of exported object by */ |
|
+/* "structure.c" */ |
|
+/*************************************************/ |
|
+ |
|
+#ifndef _STRUCTURE_H |
|
+#define _STRUCTURE_H |
|
+ |
|
+#include "parser_aux.h" // list_type |
|
+ |
|
+int _asn1_create_static_structure (asn1_node_const pointer, |
|
+ char *output_file_name, char *vector_name); |
|
+ |
|
+asn1_node _asn1_copy_structure3 (asn1_node_const source_node); |
|
+ |
|
+asn1_node _asn1_add_single_node (unsigned int type); |
|
+ |
|
+asn1_node _asn1_find_left (asn1_node_const node); |
|
+ |
|
+int |
|
+_asn1_delete_structure (list_type *e_list, asn1_node *structure, unsigned int flags); |
|
+ |
|
+#endif |
|
diff --git a/include/grub/libtasn1.h b/include/grub/libtasn1.h |
|
new file mode 100644 |
|
index 00000000000..6fd7a30dc35 |
|
--- /dev/null |
|
+++ b/include/grub/libtasn1.h |
|
@@ -0,0 +1,588 @@ |
|
+/* |
|
+ * Copyright (C) 2002-2014 Free Software Foundation, Inc. |
|
+ * |
|
+ * This file is part of LIBTASN1. |
|
+ * |
|
+ * LIBTASN1 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. |
|
+ * |
|
+ * LIBTASN1 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 LIBTASN1; if not, write to the Free Software |
|
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
|
+ * 02110-1301, USA |
|
+ * |
|
+ */ |
|
+ |
|
+/** |
|
+ * libtasn1:Short_Description: |
|
+ * |
|
+ * GNU ASN.1 library |
|
+ */ |
|
+/** |
|
+ * libtasn1:Long_Description: |
|
+ * |
|
+ * The Libtasn1 library provides Abstract Syntax Notation One (ASN.1, as |
|
+ * specified by the X.680 ITU-T recommendation) parsing and structures |
|
+ * management, and Distinguished Encoding Rules (DER, as per X.690) |
|
+ * encoding and decoding functions. |
|
+ */ |
|
+ |
|
+ |
|
+#ifndef LIBTASN1_H |
|
+#define LIBTASN1_H |
|
+ |
|
+#ifndef ASN1_API |
|
+#if defined ASN1_BUILDING && defined HAVE_VISIBILITY && HAVE_VISIBILITY |
|
+#define ASN1_API __attribute__((__visibility__("default"))) |
|
+#elif defined ASN1_BUILDING && defined _MSC_VER && ! defined ASN1_STATIC |
|
+#define ASN1_API __declspec(dllexport) |
|
+#elif defined _MSC_VER && ! defined ASN1_STATIC |
|
+#define ASN1_API __declspec(dllimport) |
|
+#else |
|
+#define ASN1_API |
|
+#endif |
|
+#endif |
|
+ |
|
+#ifdef __GNUC__ |
|
+# define __LIBTASN1_CONST__ __attribute__((const)) |
|
+# define __LIBTASN1_PURE__ __attribute__((pure)) |
|
+#else |
|
+# define __LIBTASN1_CONST__ |
|
+# define __LIBTASN1_PURE__ |
|
+#endif |
|
+ |
|
+#include <sys/types.h> |
|
+#include <time.h> |
|
+#include <stdio.h> /* for FILE* */ |
|
+ |
|
+#ifdef __cplusplus |
|
+extern "C" |
|
+{ |
|
+#endif |
|
+ |
|
+/** |
|
+ * ASN1_VERSION: |
|
+ * |
|
+ * Version of the library as a string. |
|
+ */ |
|
+#define ASN1_VERSION "4.16.0" |
|
+ |
|
+/** |
|
+ * ASN1_VERSION_MAJOR: |
|
+ * |
|
+ * Major version number of the library. |
|
+ */ |
|
+#define ASN1_VERSION_MAJOR 4 |
|
+ |
|
+/** |
|
+ * ASN1_VERSION_MINOR: |
|
+ * |
|
+ * Minor version number of the library. |
|
+ */ |
|
+#define ASN1_VERSION_MINOR 16 |
|
+ |
|
+/** |
|
+ * ASN1_VERSION_PATCH: |
|
+ * |
|
+ * Patch version number of the library. |
|
+ */ |
|
+#define ASN1_VERSION_PATCH 0 |
|
+ |
|
+/** |
|
+ * ASN1_VERSION_NUMBER: |
|
+ * |
|
+ * Version number of the library as a number. |
|
+ */ |
|
+#define ASN1_VERSION_NUMBER 0x041000 |
|
+ |
|
+ |
|
+#if defined __GNUC__ && !defined ASN1_INTERNAL_BUILD |
|
+# define _ASN1_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) |
|
+# if _ASN1_GCC_VERSION >= 30100 |
|
+# define _ASN1_GCC_ATTR_DEPRECATED __attribute__ ((__deprecated__)) |
|
+# endif |
|
+#endif |
|
+ |
|
+#ifndef _ASN1_GCC_ATTR_DEPRECATED |
|
+#define _ASN1_GCC_ATTR_DEPRECATED |
|
+#endif |
|
+ |
|
+/*****************************************/ |
|
+/* Errors returned by libtasn1 functions */ |
|
+/*****************************************/ |
|
+#define ASN1_SUCCESS 0 |
|
+#define ASN1_FILE_NOT_FOUND 1 |
|
+#define ASN1_ELEMENT_NOT_FOUND 2 |
|
+#define ASN1_IDENTIFIER_NOT_FOUND 3 |
|
+#define ASN1_DER_ERROR 4 |
|
+#define ASN1_VALUE_NOT_FOUND 5 |
|
+#define ASN1_GENERIC_ERROR 6 |
|
+#define ASN1_VALUE_NOT_VALID 7 |
|
+#define ASN1_TAG_ERROR 8 |
|
+#define ASN1_TAG_IMPLICIT 9 |
|
+#define ASN1_ERROR_TYPE_ANY 10 |
|
+#define ASN1_SYNTAX_ERROR 11 |
|
+#define ASN1_MEM_ERROR 12 |
|
+#define ASN1_MEM_ALLOC_ERROR 13 |
|
+#define ASN1_DER_OVERFLOW 14 |
|
+#define ASN1_NAME_TOO_LONG 15 |
|
+#define ASN1_ARRAY_ERROR 16 |
|
+#define ASN1_ELEMENT_NOT_EMPTY 17 |
|
+#define ASN1_TIME_ENCODING_ERROR 18 |
|
+#define ASN1_RECURSION 19 |
|
+ |
|
+/*************************************/ |
|
+/* Constants used in asn1_visit_tree */ |
|
+/*************************************/ |
|
+#define ASN1_PRINT_NAME 1 |
|
+#define ASN1_PRINT_NAME_TYPE 2 |
|
+#define ASN1_PRINT_NAME_TYPE_VALUE 3 |
|
+#define ASN1_PRINT_ALL 4 |
|
+ |
|
+/*****************************************/ |
|
+/* Constants returned by asn1_read_tag */ |
|
+/*****************************************/ |
|
+#define ASN1_CLASS_UNIVERSAL 0x00 /* old: 1 */ |
|
+#define ASN1_CLASS_APPLICATION 0x40 /* old: 2 */ |
|
+#define ASN1_CLASS_CONTEXT_SPECIFIC 0x80 /* old: 3 */ |
|
+#define ASN1_CLASS_PRIVATE 0xC0 /* old: 4 */ |
|
+#define ASN1_CLASS_STRUCTURED 0x20 |
|
+ |
|
+/*****************************************/ |
|
+/* Constants returned by asn1_read_tag */ |
|
+/*****************************************/ |
|
+#define ASN1_TAG_BOOLEAN 0x01 |
|
+#define ASN1_TAG_INTEGER 0x02 |
|
+#define ASN1_TAG_SEQUENCE 0x10 |
|
+#define ASN1_TAG_SET 0x11 |
|
+#define ASN1_TAG_OCTET_STRING 0x04 |
|
+#define ASN1_TAG_BIT_STRING 0x03 |
|
+#define ASN1_TAG_UTCTime 0x17 |
|
+#define ASN1_TAG_GENERALIZEDTime 0x18 |
|
+#define ASN1_TAG_OBJECT_ID 0x06 |
|
+#define ASN1_TAG_ENUMERATED 0x0A |
|
+#define ASN1_TAG_NULL 0x05 |
|
+#define ASN1_TAG_GENERALSTRING 0x1B |
|
+#define ASN1_TAG_NUMERIC_STRING 0x12 |
|
+#define ASN1_TAG_IA5_STRING 0x16 |
|
+#define ASN1_TAG_TELETEX_STRING 0x14 |
|
+#define ASN1_TAG_PRINTABLE_STRING 0x13 |
|
+#define ASN1_TAG_UNIVERSAL_STRING 0x1C |
|
+#define ASN1_TAG_BMP_STRING 0x1E |
|
+#define ASN1_TAG_UTF8_STRING 0x0C |
|
+#define ASN1_TAG_VISIBLE_STRING 0x1A |
|
+ |
|
+/** |
|
+ * asn1_node: |
|
+ * |
|
+ * Structure definition used for the node of the tree |
|
+ * that represents an ASN.1 DEFINITION. |
|
+ */ |
|
+typedef struct asn1_node_st asn1_node_st; |
|
+ |
|
+typedef asn1_node_st *asn1_node; |
|
+typedef const asn1_node_st *asn1_node_const; |
|
+ |
|
+/** |
|
+ * ASN1_MAX_NAME_SIZE: |
|
+ * |
|
+ * Maximum number of characters of a name |
|
+ * inside a file with ASN1 definitions. |
|
+ */ |
|
+#define ASN1_MAX_NAME_SIZE 64 |
|
+ |
|
+ |
|
+/** |
|
+ * asn1_static_node: |
|
+ * @name: Node name |
|
+ * @type: Node typ |
|
+ * @value: Node value |
|
+ * |
|
+ * For the on-disk format of ASN.1 trees, created by asn1_parser2array(). |
|
+ */ |
|
+struct asn1_static_node_st |
|
+{ |
|
+ const char *name; /* Node name */ |
|
+ unsigned int type; /* Node type */ |
|
+ const void *value; /* Node value */ |
|
+}; |
|
+typedef struct asn1_static_node_st asn1_static_node; |
|
+ |
|
+/* List of constants for field type of node_asn */ |
|
+#define ASN1_ETYPE_INVALID 0 |
|
+#define ASN1_ETYPE_CONSTANT 1 |
|
+#define ASN1_ETYPE_IDENTIFIER 2 |
|
+#define ASN1_ETYPE_INTEGER 3 |
|
+#define ASN1_ETYPE_BOOLEAN 4 |
|
+#define ASN1_ETYPE_SEQUENCE 5 |
|
+#define ASN1_ETYPE_BIT_STRING 6 |
|
+#define ASN1_ETYPE_OCTET_STRING 7 |
|
+#define ASN1_ETYPE_TAG 8 |
|
+#define ASN1_ETYPE_DEFAULT 9 |
|
+#define ASN1_ETYPE_SIZE 10 |
|
+#define ASN1_ETYPE_SEQUENCE_OF 11 |
|
+#define ASN1_ETYPE_OBJECT_ID 12 |
|
+#define ASN1_ETYPE_ANY 13 |
|
+#define ASN1_ETYPE_SET 14 |
|
+#define ASN1_ETYPE_SET_OF 15 |
|
+#define ASN1_ETYPE_DEFINITIONS 16 |
|
+#define ASN1_ETYPE_CHOICE 18 |
|
+#define ASN1_ETYPE_IMPORTS 19 |
|
+#define ASN1_ETYPE_NULL 20 |
|
+#define ASN1_ETYPE_ENUMERATED 21 |
|
+#define ASN1_ETYPE_GENERALSTRING 27 |
|
+#define ASN1_ETYPE_NUMERIC_STRING 28 |
|
+#define ASN1_ETYPE_IA5_STRING 29 |
|
+#define ASN1_ETYPE_TELETEX_STRING 30 |
|
+#define ASN1_ETYPE_PRINTABLE_STRING 31 |
|
+#define ASN1_ETYPE_UNIVERSAL_STRING 32 |
|
+#define ASN1_ETYPE_BMP_STRING 33 |
|
+#define ASN1_ETYPE_UTF8_STRING 34 |
|
+#define ASN1_ETYPE_VISIBLE_STRING 35 |
|
+#define ASN1_ETYPE_UTC_TIME 36 |
|
+#define ASN1_ETYPE_GENERALIZED_TIME 37 |
|
+ |
|
+/** |
|
+ * ASN1_DELETE_FLAG_ZEROIZE: |
|
+ * |
|
+ * Used by: asn1_delete_structure2() |
|
+ * |
|
+ * Zeroize values prior to deinitialization. |
|
+ */ |
|
+#define ASN1_DELETE_FLAG_ZEROIZE 1 |
|
+ |
|
+/** |
|
+ * ASN1_DECODE_FLAG_ALLOW_PADDING: |
|
+ * |
|
+ * Used by: asn1_der_decoding2() |
|
+ * |
|
+ * This flag would allow arbitrary data past the DER data. |
|
+ */ |
|
+#define ASN1_DECODE_FLAG_ALLOW_PADDING 1 |
|
+/** |
|
+ * ASN1_DECODE_FLAG_STRICT_DER: |
|
+ * |
|
+ * Used by: asn1_der_decoding2() |
|
+ * |
|
+ * This flag would ensure that no BER decoding takes place. |
|
+ */ |
|
+#define ASN1_DECODE_FLAG_STRICT_DER (1<<1) |
|
+/** |
|
+ * ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME: |
|
+ * |
|
+ * Used by: asn1_der_decoding2() |
|
+ * |
|
+ * This flag will tolerate Time encoding errors when in strict DER. |
|
+ */ |
|
+#define ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME (1<<2) |
|
+ |
|
+ |
|
+/** |
|
+ * asn1_data_node_st: |
|
+ * @name: Node name |
|
+ * @value: Node value |
|
+ * @value_len: Node value size |
|
+ * @type: Node value type (ASN1_ETYPE_*) |
|
+ * |
|
+ * Data node inside a #asn1_node structure. |
|
+ */ |
|
+struct asn1_data_node_st |
|
+{ |
|
+ const char *name; /* Node name */ |
|
+ const void *value; /* Node value */ |
|
+ unsigned int value_len; /* Node value size */ |
|
+ unsigned int type; /* Node value type (ASN1_ETYPE_*) */ |
|
+}; |
|
+typedef struct asn1_data_node_st asn1_data_node_st; |
|
+ |
|
+/***********************************/ |
|
+/* Fixed constants */ |
|
+/***********************************/ |
|
+ |
|
+/** |
|
+ * ASN1_MAX_ERROR_DESCRIPTION_SIZE: |
|
+ * |
|
+ * Maximum number of characters |
|
+ * of a description message |
|
+ * (null character included). |
|
+ */ |
|
+#define ASN1_MAX_ERROR_DESCRIPTION_SIZE 128 |
|
+ |
|
+/***********************************/ |
|
+/* Functions definitions */ |
|
+/***********************************/ |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_parser2tree (const char *file, |
|
+ asn1_node * definitions, char *error_desc); |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_parser2array (const char *inputFileName, |
|
+ const char *outputFileName, |
|
+ const char *vectorName, char *error_desc); |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_array2tree (const asn1_static_node * array, |
|
+ asn1_node * definitions, char *errorDescription); |
|
+ |
|
+extern ASN1_API void |
|
+ asn1_print_structure (FILE * out, asn1_node_const structure, |
|
+ const char *name, int mode); |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_create_element (asn1_node_const definitions, |
|
+ const char *source_name, asn1_node * element); |
|
+ |
|
+extern ASN1_API int asn1_delete_structure (asn1_node * structure); |
|
+ |
|
+extern ASN1_API int asn1_delete_structure2 (asn1_node * structure, unsigned int flags); |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_delete_element (asn1_node structure, const char *element_name); |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_write_value (asn1_node node_root, const char *name, |
|
+ const void *ivalue, int len); |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_read_value (asn1_node_const root, const char *name, |
|
+ void *ivalue, int *len); |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_read_value_type (asn1_node_const root, const char *name, |
|
+ void *ivalue, int *len, unsigned int *etype); |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_read_node_value (asn1_node_const node, asn1_data_node_st * data); |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_number_of_elements (asn1_node_const element, const char *name, int *num); |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_der_coding (asn1_node_const element, const char *name, |
|
+ void *ider, int *len, char *ErrorDescription); |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_der_decoding2 (asn1_node *element, const void *ider, |
|
+ int *max_ider_len, unsigned int flags, |
|
+ char *errorDescription); |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_der_decoding (asn1_node * element, const void *ider, |
|
+ int ider_len, char *errorDescription); |
|
+ |
|
+/* Do not use. Use asn1_der_decoding() instead. */ |
|
+extern ASN1_API int |
|
+ asn1_der_decoding_element (asn1_node * structure, |
|
+ const char *elementName, |
|
+ const void *ider, int len, |
|
+ char *errorDescription) _ASN1_GCC_ATTR_DEPRECATED; |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_der_decoding_startEnd (asn1_node element, |
|
+ const void *ider, int ider_len, |
|
+ const char *name_element, |
|
+ int *start, int *end); |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_expand_any_defined_by (asn1_node_const definitions, asn1_node * element); |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_expand_octet_string (asn1_node_const definitions, |
|
+ asn1_node * element, |
|
+ const char *octetName, const char *objectName); |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_read_tag (asn1_node_const root, const char *name, |
|
+ int *tagValue, int *classValue); |
|
+ |
|
+extern ASN1_API const char *asn1_find_structure_from_oid (asn1_node_const |
|
+ definitions, |
|
+ const char |
|
+ *oidValue); |
|
+ |
|
+__LIBTASN1_PURE__ |
|
+extern ASN1_API const char *asn1_check_version (const char *req_version); |
|
+ |
|
+__LIBTASN1_PURE__ |
|
+extern ASN1_API const char *asn1_strerror (int error); |
|
+ |
|
+extern ASN1_API void asn1_perror (int error); |
|
+ |
|
+#define ASN1_MAX_TAG_SIZE 4 |
|
+#define ASN1_MAX_LENGTH_SIZE 9 |
|
+#define ASN1_MAX_TL_SIZE (ASN1_MAX_TAG_SIZE+ASN1_MAX_LENGTH_SIZE) |
|
+extern ASN1_API long |
|
+ asn1_get_length_der (const unsigned char *der, int der_len, int *len); |
|
+ |
|
+extern ASN1_API long |
|
+ asn1_get_length_ber (const unsigned char *ber, int ber_len, int *len); |
|
+ |
|
+extern ASN1_API void |
|
+ asn1_length_der (unsigned long int len, unsigned char *der, int *der_len); |
|
+ |
|
+/* Other utility functions. */ |
|
+ |
|
+extern ASN1_API |
|
+ int asn1_decode_simple_der (unsigned int etype, const unsigned char *der, |
|
+ unsigned int _der_len, |
|
+ const unsigned char **str, |
|
+ unsigned int *str_len); |
|
+ |
|
+extern ASN1_API |
|
+ int asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, |
|
+ unsigned int _der_len, |
|
+ unsigned char **str, |
|
+ unsigned int *str_len, |
|
+ unsigned int *ber_len); |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_encode_simple_der (unsigned int etype, const unsigned char *str, |
|
+ unsigned int str_len, unsigned char *tl, |
|
+ unsigned int *tl_len); |
|
+ |
|
+extern ASN1_API asn1_node |
|
+ asn1_find_node (asn1_node_const pointer, const char *name); |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_copy_node (asn1_node dst, const char *dst_name, |
|
+ asn1_node_const src, const char *src_name); |
|
+extern ASN1_API asn1_node |
|
+ asn1_dup_node (asn1_node_const src, const char *src_name); |
|
+ |
|
+/* Internal and low-level DER utility functions. */ |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_get_tag_der (const unsigned char *der, int der_len, |
|
+ unsigned char *cls, int *len, unsigned long *tag); |
|
+ |
|
+extern ASN1_API void |
|
+ asn1_octet_der (const unsigned char *str, int str_len, |
|
+ unsigned char *der, int *der_len); |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_get_octet_der (const unsigned char *der, int der_len, |
|
+ int *ret_len, unsigned char *str, |
|
+ int str_size, int *str_len); |
|
+ |
|
+extern ASN1_API void asn1_bit_der (const unsigned char *str, int bit_len, |
|
+ unsigned char *der, int *der_len); |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_get_bit_der (const unsigned char *der, int der_len, |
|
+ int *ret_len, unsigned char *str, |
|
+ int str_size, int *bit_len); |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_get_object_id_der (const unsigned char *der, |
|
+ int der_len, int *ret_len, |
|
+ char *str, int str_size); |
|
+ |
|
+extern ASN1_API int |
|
+ asn1_object_id_der (const char *str, unsigned char *der, int *der_len, |
|
+ unsigned flags); |
|
+ |
|
+/* Compatibility types */ |
|
+ |
|
+/** |
|
+ * asn1_retCode: |
|
+ * |
|
+ * Type formerly returned by libtasn1 functions. |
|
+ * |
|
+ * Deprecated: 3.0: Use int instead. |
|
+ */ |
|
+typedef int asn1_retCode; |
|
+ |
|
+/** |
|
+ * node_asn_struct: |
|
+ * |
|
+ * Compat #define. |
|
+ * |
|
+ * Deprecated: 3.0: Use #asn1_node instead. |
|
+ */ |
|
+#define node_asn_struct asn1_node_st |
|
+ |
|
+/** |
|
+ * node_asn: |
|
+ * |
|
+ * Compat #define. |
|
+ * |
|
+ * Deprecated: 3.0: Use #asn1_node instead. |
|
+ */ |
|
+#define node_asn asn1_node_st |
|
+ |
|
+/** |
|
+ * ASN1_TYPE: |
|
+ * |
|
+ * Compat #define. |
|
+ * |
|
+ * Deprecated: 3.0: Use #asn1_node instead. |
|
+ */ |
|
+#define ASN1_TYPE asn1_node |
|
+ |
|
+/** |
|
+ * ASN1_TYPE_EMPTY: |
|
+ * |
|
+ * Compat #define. |
|
+ * |
|
+ * Deprecated: 3.0: Use NULL instead. |
|
+ */ |
|
+#define ASN1_TYPE_EMPTY NULL |
|
+ |
|
+/** |
|
+ * static_struct_asn: |
|
+ * |
|
+ * Compat #define. |
|
+ * |
|
+ * Deprecated: 3.0: Use #asn1_static_node instead. |
|
+ */ |
|
+#define static_struct_asn asn1_static_node_st |
|
+ |
|
+/** |
|
+ * ASN1_ARRAY_TYPE: |
|
+ * |
|
+ * Compat #define. |
|
+ * |
|
+ * Deprecated: 3.0: Use #asn1_static_node instead. |
|
+ */ |
|
+#define ASN1_ARRAY_TYPE asn1_static_node |
|
+ |
|
+/** |
|
+ * asn1_static_node_t: |
|
+ * |
|
+ * Compat #define. |
|
+ * |
|
+ * Deprecated: 3.0: Use #asn1_static_node instead. |
|
+ */ |
|
+#define asn1_static_node_t asn1_static_node |
|
+ |
|
+/** |
|
+ * node_data_struct: |
|
+ * |
|
+ * Compat #define. |
|
+ * |
|
+ * Deprecated: 3.0: Use #asn1_data_node_st instead. |
|
+ */ |
|
+#define node_data_struct asn1_data_node_st |
|
+ |
|
+/** |
|
+ * ASN1_DATA_NODE: |
|
+ * |
|
+ * Compat #define. |
|
+ * |
|
+ * Deprecated: 3.0: Use #asn1_data_node_st instead. |
|
+ */ |
|
+#define ASN1_DATA_NODE asn1_data_node_st |
|
+ |
|
+#ifdef __cplusplus |
|
+} |
|
+#endif |
|
+ |
|
+#endif /* LIBTASN1_H */ |
|
diff --git a/grub-core/lib/libtasn1/LICENSE b/grub-core/lib/libtasn1/LICENSE |
|
new file mode 100644 |
|
index 00000000000..e8b3628db9b |
|
--- /dev/null |
|
+++ b/grub-core/lib/libtasn1/LICENSE |
|
@@ -0,0 +1,16 @@ |
|
+LICENSING |
|
+========= |
|
+ |
|
+The libtasn1 library is released under the GNU Lesser General Public |
|
+License (LGPL) version 2.1 or later; see [COPYING.LESSER](doc/COPYING.LESSER) |
|
+for the license terms. |
|
+ |
|
+The GNU LGPL applies to the main libtasn1 library, while the |
|
+included applications library are under the GNU GPL version 3. |
|
+The libtasn1 library is located in the lib directory, while the applications |
|
+in src/. |
|
+ |
|
+The documentation in doc/ is under the GNU FDL license 1.3. |
|
+ |
|
+For any copyright year range specified as YYYY-ZZZZ in this package |
|
+note that the range specifies every single year in that closed interval. |
|
diff --git a/grub-core/lib/libtasn1/README.md b/grub-core/lib/libtasn1/README.md |
|
new file mode 100644 |
|
index 00000000000..50a8642296c |
|
--- /dev/null |
|
+++ b/grub-core/lib/libtasn1/README.md |
|
@@ -0,0 +1,91 @@ |
|
+|Branch|CI system|Status| |
|
+|:----:|:-------:|-----:| |
|
+|Master|Gitlab|[![build status](https://gitlab.com/gnutls/libtasn1/badges/master/pipeline.svg)](https://gitlab.com/gnutls/libtasn1/commits/master)[![coverage report](https://gitlab.com/gnutls/libtasn1/badges/master/coverage.svg)](https://gnutls.gitlab.io/libtasn1/coverage)| |
|
+ |
|
+# libtasn1 |
|
+ |
|
+This is GNU Libtasn1, a small ASN.1 library. |
|
+ |
|
+The C library (libtasn1.*) is licensed under the GNU Lesser General |
|
+Public License version 2.1 or later. See the file COPYING.LIB. |
|
+ |
|
+The command line tool, self tests, examples, and other auxilliary |
|
+files, are licensed under the GNU General Public License version 3.0 |
|
+or later. See the file COPYING. |
|
+ |
|
+## Building the library |
|
+ |
|
+We require several tools to build the software, including: |
|
+ |
|
+* [Make](https://www.gnu.org/software/make/) |
|
+* [Automake](https://www.gnu.org/software/automake/) (use 1.11.3 or later) |
|
+* [Autoconf](https://www.gnu.org/software/autoconf/) |
|
+* [Libtool](https://www.gnu.org/software/libtool/) |
|
+* [Texinfo](https://www.gnu.org/software/texinfo/) |
|
+* [help2man](http://www.gnu.org/software/help2man/) |
|
+* [Tar](https://www.gnu.org/software/tar/) |
|
+* [Gzip](https://www.gnu.org/software/gzip/) |
|
+* [bison](https://www.gnu.org/software/bison/) |
|
+* [Texlive & epsf](https://www.tug.org/texlive/) (for PDF manual) |
|
+* [GTK-DOC](https://www.gtk.org/gtk-doc/) (for API manual) |
|
+* [Git](https://git-scm.com/) |
|
+* [libabigail](https://pagure.io/libabigail/) (for abi comparison in make dist) |
|
+* [Valgrind](https://valgrind.org/) (optional) |
|
+ |
|
+The required software is typically distributed with your operating |
|
+system, and the instructions for installing them differ. Here are |
|
+some hints: |
|
+ |
|
+gNewSense/Debian/Ubuntu: |
|
+``` |
|
+sudo apt-get install make git-core autoconf automake libtool |
|
+sudo apt-get install texinfo texlive texlive-generic-recommended texlive-extra-utils |
|
+sudo apt-get install help2man gtk-doc-tools valgrind abigail-tools |
|
+``` |
|
+ |
|
+The next step is to run autoreconf, ./configure, etc: |
|
+ |
|
+``` |
|
+$ ./bootstrap |
|
+``` |
|
+ |
|
+Then build the project normally: |
|
+ |
|
+``` |
|
+$ make |
|
+$ make check |
|
+``` |
|
+ |
|
+Happy hacking! |
|
+ |
|
+ |
|
+## Manual |
|
+ |
|
+The manual is in the `doc/` directory of the release. You can also browse |
|
+the manual online at: |
|
+ |
|
+ - https://gnutls.gitlab.io/libtasn1/ |
|
+ |
|
+ |
|
+## Code coverage report |
|
+ |
|
+The coverage report is at: |
|
+ |
|
+ - https://gnutls.gitlab.io/libtasn1/coverage |
|
+ |
|
+ |
|
+## Issue trackers |
|
+ |
|
+ - [Main issue tracker](https://gitlab.com/gnutls/libtasn1/issues) |
|
+ - [oss-fuzz found issues](https://bugs.chromium.org/p/oss-fuzz/issues/list?q=libtasn1&can=2) |
|
+ |
|
+ |
|
+## Homepage |
|
+ |
|
+The project homepage at the gnu site is at: |
|
+ |
|
+http://www.gnu.org/software/libtasn1/ |
|
+ |
|
+ |
|
+For any copyright year range specified as YYYY-ZZZZ in this package |
|
+note that the range specifies every single year in that closed interval.
|
|
|