diff --git a/doc/crypt.tex b/doc/crypt.tex
index 33d021b07..d246f9a19 100644
--- a/doc/crypt.tex
+++ b/doc/crypt.tex
@@ -5563,6 +5563,10 @@ \chapter{Standards Support}
void *data;
unsigned long size;
int used;
+ int optional;
+ ltc_asn1_class class;
+ ltc_asn1_pc pc;
+ ulong64 tag;
struct ltc_asn1_list_ *prev, *next,
*child, *parent;
} ltc_asn1_list;
@@ -5625,9 +5629,8 @@ \chapter{Standards Support}
\hline LTC\_ASN1\_SETOF & SET OF \\
\hline LTC\_ASN1\_RAW\_BIT\_STRING & BIT STRING (one octet per char) \\
\hline LTC\_ASN1\_TELETEX\_STRING & TELETEX STRING (one octet per char) \\
-\hline LTC\_ASN1\_CONSTRUCTED & A constructed type that is not SEQUENCE or SET \\
-\hline LTC\_ASN1\_CONTEXT\_SPECIFIC & A context-specific type \\
\hline LTC\_ASN1\_GENERALIZEDTIME & GeneralizedTime (see ltc\_generalizedtime structure) \\
+\hline LTC\_ASN1\_CUSTOM\_TYPE & A custom type (see LTC\_SET\_ASN1\_CUSTOM\_XXX macros) \\
\hline
\end{tabular}
\caption{List of ASN.1 Supported Types}
@@ -5636,6 +5639,36 @@ \chapter{Standards Support}
\end{center}
\end{figure}
+\index{LTC\_ASN1\_CUSTOM\_TYPE}
+\index{LTC\_SET\_ASN1\_CUSTOM\_CONSTRUCTED macro}
+\index{LTC\_SET\_ASN1\_CUSTOM\_PRIMITIVE macro}
+
+To be able to encode and decode all other valid ASN.1 Identifiers, such as Context-Specific types the macros
+\textit{LTC\_SET\_ASN1\_CUSTOM\_CONSTRUCTED(list, index, Class, Tag, Data)} resp.
+\textit{LTC\_SET\_ASN1\_CUSTOM\_PRIMITIVE(list, index, Class, Tag, Type, Data, Size)} have been provided.
+
+They will assign to the \textit{index}th position in the \textit{list} the Identifier-triplet (Class, CONSTRUCTED resp. PRIMITIVE, Tag).
+An example usage would be:
+
+\begin{small}
+\begin{verbatim}
+...
+ltc_asn1_list sequence[4], custom[1];
+unsigned long three=3;
+unsigned char buf[128];
+
+LTC_SET_ASN1(sequence, 0, LTC_ASN1_IA5_STRING, "hello", 5);
+LTC_SET_ASN1(sequence, 1, LTC_ASN1_SHORT_INTEGER, &three, 1);
+LTC_SET_ASN1(sequence, 2, LTC_ASN1_NULL, NULL, 0);
+LTC_SET_ASN1_CUSTOM_PRIMITIVE(sequence, 3, LTC_ASN1_CL_CONTEXT_SPECIFIC, 23, \
+ LTC_ASN1_OCTET_STRING, buf, sizeof(buf));
+
+LTC_SET_ASN1_CUSTOM_CONSTRUCTED(custom, 0, LTC_ASN1_CL_CONTEXT_SPECIFIC, 0, sequence);
+\end{verbatim}
+\end{small}
+
+This would allow (un)pack'ing the given \textit{sequence} from/in the context-specific tag \textit{[0]}.
+
\subsection{SEQUENCE Type}
The SEQUENCE data type is a collection of other ASN.1 data types encapsulated with a small header which is a useful way of sending multiple data types in one packet.
@@ -5660,6 +5693,7 @@ \subsubsection{SEQUENCE Encoding}
\subsubsection{SEQUENCE Decoding}
\index{der\_decode\_sequence()}
+\index{der\_decode\_sequence\_strict()}
Decoding a SEQUENCE is similar to encoding. You set up an array of \textbf{ltc\_asn1\_list} where in this case the \textit{size} member is the maximum size
(in certain cases). For types such as IA5 STRING, BIT STRING, OCTET STRING (etc) the \textit{size} field is updated after successful decoding to reflect how many
@@ -5670,18 +5704,27 @@ \subsubsection{SEQUENCE Decoding}
unsigned long inlen,
ltc_asn1_list *list,
unsigned long outlen);
+
+int der_decode_sequence_strict(const unsigned char *in,
+ unsigned long inlen,
+ ltc_asn1_list *list,
+ unsigned long outlen);
\end{verbatim}
This will decode upto \textit{outlen} items from the input buffer \textit{in} of length \textit{inlen} octets. The function will stop (gracefully) when it runs out of items to decode.
It will fail (for among other reasons) when it runs out of input bytes to read, a data type is invalid or a heap failure occurred.
+The regular variant will return \textbf{CRYPT\_INPUT\_TOO\_LONG} in cases where there was more data to be decoded given through \textit{inlen} than the ASN.1 length-tag specified.
+The strict variant \textit{der\_decode\_sequence\_strict()} returns an error in this case.
For the following types the \textit{size} field will be updated to reflect the number of units read of the given type.
\begin{enumerate}
- \item BIT STRING
+ \item (RAW) BIT STRING
\item OCTET STRING
\item OBJECT IDENTIFIER
\item IA5 STRING
\item PRINTABLE STRING
+ \item TELETEX STRING
+ \item UTF8 STRING
\end{enumerate}
\subsubsection{SEQUENCE Length}
@@ -6139,32 +6182,53 @@ \subsection{ASN.1 CHOICE}
\textit{outlen} elements. The \textit{inlen} field will be updated with the length of the decoded data type, as well as the respective entry in the \textit{list} field
will have the \textit{used} flag set to non--zero to reflect it was the data type decoded.
+\subsection{ASN.1 Custom Types}
+
+To be able to represent all other valid types besides the primitive types having their own decoder, the \textit{custom\_type} de- and encoders are provided.
+
+\index{der\_encode\_custom\_type()} \index{der\_decode\_custom\_type()} \index{der\_length\_custom\_type()} \index{LTC\_ASN1\_CUSTOM\_TYPE}
+\begin{verbatim}
+int der_encode_custom_type(const ltc_asn1_list *root,
+ unsigned char *out, unsigned long *outlen);
+
+int der_decode_custom_type(const unsigned char *in, unsigned long inlen,
+ ltc_asn1_list *root);
+
+int der_length_custom_type(const ltc_asn1_list *root,
+ unsigned long *outlen,
+ unsigned long *payloadlen);
+\end{verbatim}
+
+The usage of this de- and encoder is a bit different than the others since the type to be encoded has to be passed to the function.
+Therefore the \textit{root} parameter identifies the type that should be encoded which has been set by the \textit{LTC\_SET\_ASN1}
+and \textit{LTC\_SET\_ASN1\_IDENTIFIER}, resp. \textit{LTC\_SET\_ASN1\_CUSTOM} macros.
+The value to de-/encode has to be linked through the \textit{data} argument of the \textit{LTC\_SET\_ASN1} macro, as done for sequences.
+The value that should be de-/encoded can either be a primitive or a constructed type.
+
\subsection{ASN.1 Flexi Decoder}
-The ASN.1 \textit{flexi} decoder allows the developer to decode arbitrary ASN.1 DER packets (provided they use data types LibTomCrypt supports) without first knowing
-the structure of the data. Where der\_decode\_sequence() requires the developer to specify the data types to decode in advance the flexi decoder is entirely
-free form.
+
+The ASN.1 \textit{flexi} decoder allows the developer to decode arbitrary ASN.1 DER packets without first knowing the structure of the data.
+Where der\_decode\_sequence() requires the developer to specify the data types to decode in advance the flexi decoder is entirely free form.
The flexi decoder uses the same \textit{ltc\_asn1\_list} but instead of being stored in an array it uses the linked list pointers \textit{prev}, \textit{next}, \textit{parent}
-and \textit{child}. The list works as a \textit{doubly-linked list} structure where decoded items at the same level are siblings (using next and prev) and items
-encoded in a SEQUENCE are stored as a child element.
+and \textit{child}. The list works as a \textit{doubly-linked list} structure where decoded items at the same level are siblings (using \textit{next} and \textit{prev}) and items
+encoded in a SEQUENCE are stored as a \textit{child} element.
-When a SEQUENCE or SET has been encountered a SEQUENCE (or SET resp.) item will be added as a sibling (e.g. list.type == LTC\_ASN1\_SEQUENCE) and the child
+When a SEQUENCE or SET has been encountered a SEQUENCE (or SET resp.) item will be added as a sibling (e.g. list.type == LTC\_ASN1\_SEQUENCE) and the \textit{child}
pointer points to a new list of items contained within the object.
\index{der\_decode\_sequence\_flexi()}
-\index{LTC\_ASN1\_CONSTRUCTED}
-\index{LTC\_ASN1\_CONTEXT\_SPECIFIC}
\begin{verbatim}
int der_decode_sequence_flexi(const unsigned char *in,
unsigned long *inlen,
- ltc_asn1_list **out);
+ ltc_asn1_list **out);
\end{verbatim}
This will decode items in the \textit{in} buffer of max input length \textit{inlen} and store the newly created pointer to the list in \textit{out}. This function allocates
all required memory for the decoding. It stores the number of octets read back into \textit{inlen}.
The function will terminate when either it hits an invalid ASN.1 tag, or it reads \textit{inlen} octets. An early termination is a soft error, and returns
-normally. The decoded list \textit{out} will point to the very first element of the list (e.g. both parent and prev pointers will be \textbf{NULL}).
+normally. The decoded list \textit{out} will point to the very first element of the list (i.e. both parent and prev pointers will be \textbf{NULL}).
An invalid decoding will terminate the process, and free the allocated memory automatically.
@@ -6175,18 +6239,12 @@ \subsection{ASN.1 Flexi Decoder}
This can be detected by checking for \textit{child} elements with
type \textbf{LTC\_ASN1\_EOL} after decoding.
-As of v1.18.0 the flexi decoder will also decode arbitrary constructed types
-other than SEQUENCE and SET. The \textit{type} field will be set to
-\textbf{LTC\_ASN1\_CONSTRUCTED} and the plain identifier that was indicated in the ASN.1
-encoding is stored in the \textit{used} field. Further decoding is done in the
-same way as if it were a SEQUENCE or SET.
-
-Also as of v1.18.0 the flexi decoder is capable to handle
-\textit{context-specific} encodings. The \textit{type} field will be set to
-\textbf{LTC\_ASN1\_CONTEXT\_SPECIFIC} and the plain identifier that was indicated
-in the ASN.1 encoding is stored in the \textit{used} field. Encapsulated data
-in the \textit{context-specific} encoding is copied to newly allocated memory
-and is accessible through the \textit{data} field.
+The v1.18.0 of the library had support for decoding two new types, \textbf{LTC\_ASN1\_CONSTRUCTED} and \textbf{LTC\_ASN1\_CONTEXT\_SPECIFIC},
+which has been replaced in FIXME-version-next by a more complete approach.
+
+As of FIXME-version-next all ASN.1 Identifiers which don't have a decoder implemented (and thereby their own type) will be marked as
+\textbf{LTC\_ASN1\_CUSTOM\_TYPE}.
+
\textbf{Note:} the list decoded by this function is \textbf{NOT} in the correct form for der\_encode\_sequence() to use directly. You will first
have to convert the list by first storing all of the siblings in an array then storing all the children as sub-lists of a sequence using the \textit{.data}
diff --git a/libtomcrypt_VS2008.vcproj b/libtomcrypt_VS2008.vcproj
index bcb637fcd..c9b1c10f8 100644
--- a/libtomcrypt_VS2008.vcproj
+++ b/libtomcrypt_VS2008.vcproj
@@ -1849,6 +1849,54 @@
>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1960,10 +2008,6 @@
RelativePath="src\pk\asn1\der\sequence\der_decode_sequence_multi.c"
>
-
-
@@ -1972,10 +2016,6 @@
RelativePath="src\pk\asn1\der\sequence\der_encode_sequence_multi.c"
>
-
-
@@ -2062,6 +2102,18 @@
+
+
+
+
+
+
*/
int der_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...);
int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...);
+#ifdef LTC_SOURCE
+/* internal helper functions */
+int der_decode_sequence_multi_ex(const unsigned char *in, unsigned long inlen, unsigned int flags, ...);
+#endif /* LTC_SOURCE */
/* FLEXI DECODER handle unknown list decoder */
int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc_asn1_list **out);
@@ -739,6 +843,17 @@ int der_decode_generalizedtime(const unsigned char *in, unsigned long *inlen,
int der_length_generalizedtime(ltc_generalizedtime *gtime, unsigned long *outlen);
+#ifdef LTC_SOURCE
+/* internal helper functions */
+/* SUBJECT PUBLIC KEY INFO */
+int x509_encode_subject_public_key_info(unsigned char *out, unsigned long *outlen,
+ unsigned int algorithm, void* public_key, unsigned long public_key_len,
+ unsigned long parameters_type, void* parameters, unsigned long parameters_len);
+
+int x509_decode_subject_public_key_info(const unsigned char *in, unsigned long inlen,
+ unsigned int algorithm, void* public_key, unsigned long* public_key_len,
+ unsigned long parameters_type, void* parameters, unsigned long *parameters_len);
+#endif /* LTC_SOURCE */
#endif
diff --git a/src/misc/crypt/crypt_constants.c b/src/misc/crypt/crypt_constants.c
index a7418d5ec..9e76322c7 100644
--- a/src/misc/crypt/crypt_constants.c
+++ b/src/misc/crypt/crypt_constants.c
@@ -47,7 +47,7 @@ static const crypt_constant _crypt_constants[] = {
_C_STRINGIFY(CRYPT_FILE_NOTFOUND),
_C_STRINGIFY(CRYPT_PK_INVALID_TYPE),
_C_STRINGIFY(CRYPT_OVERFLOW),
- _C_STRINGIFY(CRYPT_UNUSED1),
+ _C_STRINGIFY(CRYPT_PK_ASN1_ERROR),
_C_STRINGIFY(CRYPT_INPUT_TOO_LONG),
_C_STRINGIFY(CRYPT_PK_INVALID_SIZE),
_C_STRINGIFY(CRYPT_INVALID_PRIME_SIZE),
@@ -129,9 +129,8 @@ static const crypt_constant _crypt_constants[] = {
_C_STRINGIFY(LTC_ASN1_SETOF),
_C_STRINGIFY(LTC_ASN1_RAW_BIT_STRING),
_C_STRINGIFY(LTC_ASN1_TELETEX_STRING),
- _C_STRINGIFY(LTC_ASN1_CONSTRUCTED),
- _C_STRINGIFY(LTC_ASN1_CONTEXT_SPECIFIC),
_C_STRINGIFY(LTC_ASN1_GENERALIZEDTIME),
+ _C_STRINGIFY(LTC_ASN1_CUSTOM_TYPE),
#endif
#ifdef LTC_CTR_MODE
diff --git a/src/misc/error_to_string.c b/src/misc/error_to_string.c
index 707f83594..3d1682861 100644
--- a/src/misc/error_to_string.c
+++ b/src/misc/error_to_string.c
@@ -46,7 +46,7 @@ static const char * const err_2_str[] =
"An overflow of a value was detected/prevented.",
- "UNUSED1.",
+ "An ASN.1 decoding error occurred.",
"The input was longer than expected.",
diff --git a/src/pk/asn1/der/bit/der_decode_bit_string.c b/src/pk/asn1/der/bit/der_decode_bit_string.c
index 5203fcfde..6f25cd9af 100644
--- a/src/pk/asn1/der/bit/der_decode_bit_string.c
+++ b/src/pk/asn1/der/bit/der_decode_bit_string.c
@@ -28,6 +28,7 @@ int der_decode_bit_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
unsigned long dlen, blen, x, y;
+ int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
@@ -47,27 +48,13 @@ int der_decode_bit_string(const unsigned char *in, unsigned long inlen,
x = 1;
/* get the length of the data */
- if (in[x] & 0x80) {
- /* long format get number of length bytes */
- y = in[x++] & 0x7F;
-
- /* invalid if 0 or > 2 */
- if (y == 0 || y > 2) {
- return CRYPT_INVALID_PACKET;
- }
-
- /* read the data len */
- dlen = 0;
- while (y--) {
- dlen = (dlen << 8) | (unsigned long)in[x++];
- }
- } else {
- /* short format */
- dlen = in[x++] & 0x7F;
+ y = inlen - 1;
+ if ((err = der_decode_asn1_length(in + x, &y, &dlen)) != CRYPT_OK) {
+ return err;
}
-
+ x += y;
/* is the data len too long or too short? */
- if ((dlen == 0) || (dlen + x > inlen)) {
+ if ((dlen == 0) || (dlen > (inlen - x))) {
return CRYPT_INVALID_PACKET;
}
diff --git a/src/pk/asn1/der/bit/der_decode_raw_bit_string.c b/src/pk/asn1/der/bit/der_decode_raw_bit_string.c
index 223899b33..7e7a4608b 100644
--- a/src/pk/asn1/der/bit/der_decode_raw_bit_string.c
+++ b/src/pk/asn1/der/bit/der_decode_raw_bit_string.c
@@ -31,6 +31,7 @@ int der_decode_raw_bit_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
unsigned long dlen, blen, x, y;
+ int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
@@ -50,27 +51,13 @@ int der_decode_raw_bit_string(const unsigned char *in, unsigned long inlen,
x = 1;
/* get the length of the data */
- if (in[x] & 0x80) {
- /* long format get number of length bytes */
- y = in[x++] & 0x7F;
-
- /* invalid if 0 or > 2 */
- if (y == 0 || y > 2) {
- return CRYPT_INVALID_PACKET;
- }
-
- /* read the data len */
- dlen = 0;
- while (y--) {
- dlen = (dlen << 8) | (unsigned long)in[x++];
- }
- } else {
- /* short format */
- dlen = in[x++] & 0x7F;
+ y = inlen - 1;
+ if ((err = der_decode_asn1_length(in + x, &y, &dlen)) != CRYPT_OK) {
+ return err;
}
-
+ x += y;
/* is the data len too long or too short? */
- if ((dlen == 0) || (dlen + x > inlen)) {
+ if ((dlen == 0) || (dlen > (inlen - x))) {
return CRYPT_INVALID_PACKET;
}
diff --git a/src/pk/asn1/der/bit/der_encode_bit_string.c b/src/pk/asn1/der/bit/der_encode_bit_string.c
index 2a6747902..7b2c6afac 100644
--- a/src/pk/asn1/der/bit/der_encode_bit_string.c
+++ b/src/pk/asn1/der/bit/der_encode_bit_string.c
@@ -50,16 +50,11 @@ int der_encode_bit_string(const unsigned char *in, unsigned long inlen,
y = ((inlen + 7) >> 3) + 1;
out[x++] = 0x03;
- if (y < 128) {
- out[x++] = (unsigned char)y;
- } else if (y < 256) {
- out[x++] = 0x81;
- out[x++] = (unsigned char)y;
- } else if (y < 65536) {
- out[x++] = 0x82;
- out[x++] = (unsigned char)((y>>8)&255);
- out[x++] = (unsigned char)(y&255);
+ len = *outlen - x;
+ if ((err = der_encode_asn1_length(y, out + x, &len)) != CRYPT_OK) {
+ return err;
}
+ x += len;
/* store number of zero padding bits */
out[x++] = (unsigned char)((8 - inlen) & 7);
diff --git a/src/pk/asn1/der/bit/der_encode_raw_bit_string.c b/src/pk/asn1/der/bit/der_encode_raw_bit_string.c
index 4101a1da6..e884dabe6 100644
--- a/src/pk/asn1/der/bit/der_encode_raw_bit_string.c
+++ b/src/pk/asn1/der/bit/der_encode_raw_bit_string.c
@@ -52,16 +52,11 @@ int der_encode_raw_bit_string(const unsigned char *in, unsigned long inlen,
y = ((inlen + 7) >> 3) + 1;
out[x++] = 0x03;
- if (y < 128) {
- out[x++] = (unsigned char)y;
- } else if (y < 256) {
- out[x++] = 0x81;
- out[x++] = (unsigned char)y;
- } else if (y < 65536) {
- out[x++] = 0x82;
- out[x++] = (unsigned char)((y>>8)&255);
- out[x++] = (unsigned char)(y&255);
+ len = *outlen - x;
+ if ((err = der_encode_asn1_length(y, out + x, &len)) != CRYPT_OK) {
+ return err;
}
+ x += len;
/* store number of zero padding bits */
out[x++] = (unsigned char)((8 - inlen) & 7);
diff --git a/src/pk/asn1/der/bit/der_length_bit_string.c b/src/pk/asn1/der/bit/der_length_bit_string.c
index b9c99fb17..7a6520841 100644
--- a/src/pk/asn1/der/bit/der_length_bit_string.c
+++ b/src/pk/asn1/der/bit/der_length_bit_string.c
@@ -22,24 +22,18 @@
*/
int der_length_bit_string(unsigned long nbits, unsigned long *outlen)
{
- unsigned long nbytes;
+ unsigned long nbytes, x;
+ int err;
+
LTC_ARGCHK(outlen != NULL);
/* get the number of the bytes */
nbytes = (nbits >> 3) + ((nbits & 7) ? 1 : 0) + 1;
- if (nbytes < 128) {
- /* 03 LL PP DD DD DD ... */
- *outlen = 2 + nbytes;
- } else if (nbytes < 256) {
- /* 03 81 LL PP DD DD DD ... */
- *outlen = 3 + nbytes;
- } else if (nbytes < 65536) {
- /* 03 82 LL LL PP DD DD DD ... */
- *outlen = 4 + nbytes;
- } else {
- return CRYPT_INVALID_ARG;
+ if ((err = der_length_asn1_length(nbytes, &x)) != CRYPT_OK) {
+ return err;
}
+ *outlen = 1 + x + nbytes;
return CRYPT_OK;
}
diff --git a/src/pk/asn1/der/choice/der_decode_choice.c b/src/pk/asn1/der/choice/der_decode_choice.c
index 0bfd3bb65..6e17a4b70 100644
--- a/src/pk/asn1/der/choice/der_decode_choice.c
+++ b/src/pk/asn1/der/choice/der_decode_choice.c
@@ -205,9 +205,17 @@ int der_decode_choice(const unsigned char *in, unsigned long *inlen,
}
break;
+ case LTC_ASN1_CUSTOM_TYPE:
+ if (der_decode_custom_type(in, *inlen, &list[x]) == CRYPT_OK) {
+ if (der_length_custom_type(&list[x], &z, NULL) == CRYPT_OK) {
+ list[x].used = 1;
+ *inlen = z;
+ return CRYPT_OK;
+ }
+ }
+ break;
+
case LTC_ASN1_CHOICE:
- case LTC_ASN1_CONSTRUCTED:
- case LTC_ASN1_CONTEXT_SPECIFIC:
case LTC_ASN1_EOL:
return CRYPT_INVALID_ARG;
}
diff --git a/src/pk/asn1/der/custom_type/der_decode_custom_type.c b/src/pk/asn1/der/custom_type/der_decode_custom_type.c
new file mode 100644
index 000000000..64c0cf6c6
--- /dev/null
+++ b/src/pk/asn1/der/custom_type/der_decode_custom_type.c
@@ -0,0 +1,420 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+
+/**
+ @file der_decode_custom_type.c
+ ASN.1 DER, decode a Custom type, Steffen Jaeckel
+*/
+
+#ifdef LTC_DER
+
+/**
+ Decode a Custom type
+ @param in The DER encoded input
+ @param inlen The size of the input
+ @param root The item that defines the custom type to decode
+ @return CRYPT_OK on success
+*/
+int der_decode_custom_type(const unsigned char *in, unsigned long inlen,
+ ltc_asn1_list *root)
+{
+ LTC_ARGCHK(root != NULL);
+ return der_decode_custom_type_ex(in, inlen, root, NULL, 0, LTC_DER_SEQ_ORDERED | LTC_DER_SEQ_RELAXED);
+}
+
+/**
+ Extended-decode a Custom type
+
+ This function is used to decode custom types and sequences/sets
+ For custom types root is used
+ For sequences/sets list and outlen are used
+
+ @param in The DER encoded input
+ @param inlen The size of the input
+ @param root The item that defines the custom type to decode
+ @param list The list of items to decode
+ @param outlen The number of items in the list
+ @param flags c.f. enum ltc_der_seq
+ @return CRYPT_OK on success
+*/
+int der_decode_custom_type_ex(const unsigned char *in, unsigned long inlen,
+ ltc_asn1_list *root,
+ ltc_asn1_list *list, unsigned long outlen,
+ unsigned int flags)
+{
+ int err, seq_err, i, ordered;
+ ltc_asn1_type type;
+ ltc_asn1_list ident;
+ unsigned long size, x, y, z, blksize;
+ unsigned char* in_new = NULL;
+ void *data;
+
+ LTC_ARGCHK(in != NULL);
+
+ /* get blk size */
+ if (inlen < 2) {
+ return CRYPT_INVALID_PACKET;
+ }
+ x = 0;
+
+ if (root == NULL) {
+ LTC_ARGCHK(list != NULL);
+
+ /* sequence type? We allow 0x30 SEQUENCE and 0x31 SET since fundamentally they're the same structure */
+ if (in[x] != 0x30 && in[x] != 0x31) {
+ return CRYPT_INVALID_PACKET;
+ }
+ ++x;
+ } else {
+ if (root->type != LTC_ASN1_CUSTOM_TYPE) {
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* Alloc a copy of the data for primitive handling. */
+ if (root->pc == LTC_ASN1_PC_PRIMITIVE) {
+ in_new = XMALLOC(inlen);
+ if (in_new == NULL) {
+ return CRYPT_MEM;
+ }
+ XMEMCPY(in_new, in, inlen);
+ in = in_new;
+ }
+
+ y = inlen;
+ if ((err = der_decode_asn1_identifier(in, &y, &ident)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ if ((ident.type != root->type) ||
+ (ident.class != root->class) ||
+ (ident.pc != root->pc) ||
+ (ident.tag != root->tag)) {
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+ x += y;
+
+ list = root->data;
+ outlen = root->size;
+ }
+
+ if (root != NULL && root->pc == LTC_ASN1_PC_PRIMITIVE) {
+ if (((unsigned long)root->used >= der_asn1_type_to_identifier_map_sz) ||
+ (der_asn1_type_to_identifier_map[root->used] == -1)) {
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+
+ root->type = (ltc_asn1_type)root->used;
+ list = root;
+ outlen = 1;
+
+ x -= 1;
+ in_new[x] = (unsigned char)der_asn1_type_to_identifier_map[list[0].type];
+ blksize = inlen - x;
+ } else {
+
+ y = inlen - x;
+ if ((err = der_decode_asn1_length(&in[x], &y, &blksize)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ x += y;
+ }
+
+ /* would this blksize overflow? */
+ if (blksize > (inlen - x)) {
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+
+ /* mark all as unused */
+ for (i = 0; i < (int)outlen; i++) {
+ list[i].used = 0;
+ }
+ ordered = flags & LTC_DER_SEQ_ORDERED;
+
+ /* ok read data */
+ seq_err = CRYPT_OK;
+ blksize += x;
+ inlen -= x;
+ for (i = 0; i < (int)outlen; i++) {
+ z = 0;
+ type = list[i].type;
+ size = list[i].size;
+ data = list[i].data;
+ if (!ordered && list[i].used == 1) { continue; }
+
+ if (type == LTC_ASN1_EOL) {
+ break;
+ }
+
+ if (root != NULL && root->pc == LTC_ASN1_PC_PRIMITIVE && i != 0) {
+ err = CRYPT_PK_ASN1_ERROR;
+ goto LBL_ERR;
+ }
+
+ switch (type) {
+ case LTC_ASN1_BOOLEAN:
+ z = inlen;
+ if ((err = der_decode_boolean(in + x, z, ((int *)data))) != CRYPT_OK) {
+ if (!ordered || list[i].optional) { continue; }
+ goto LBL_ERR;
+ }
+ if ((err = der_length_boolean(&z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_INTEGER:
+ z = inlen;
+ if ((err = der_decode_integer(in + x, z, data)) != CRYPT_OK) {
+ if (!ordered || list[i].optional) { continue; }
+ goto LBL_ERR;
+ }
+ if ((err = der_length_integer(data, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_SHORT_INTEGER:
+ z = inlen;
+ if ((err = der_decode_short_integer(in + x, z, data)) != CRYPT_OK) {
+ if (!ordered || list[i].optional) { continue; }
+ goto LBL_ERR;
+ }
+ if ((err = der_length_short_integer(((unsigned long*)data)[0], &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+
+ break;
+
+ case LTC_ASN1_BIT_STRING:
+ z = inlen;
+ if ((err = der_decode_bit_string(in + x, z, data, &size)) != CRYPT_OK) {
+ if (!ordered || list[i].optional) { continue; }
+ goto LBL_ERR;
+ }
+ list[i].size = size;
+ if ((err = der_length_bit_string(size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_RAW_BIT_STRING:
+ z = inlen;
+ if ((err = der_decode_raw_bit_string(in + x, z, data, &size)) != CRYPT_OK) {
+ if (!ordered || list[i].optional) { continue; }
+ goto LBL_ERR;
+ }
+ list[i].size = size;
+ if ((err = der_length_bit_string(size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_OCTET_STRING:
+ z = inlen;
+ if ((err = der_decode_octet_string(in + x, z, data, &size)) != CRYPT_OK) {
+ if (!ordered || list[i].optional) { continue; }
+ goto LBL_ERR;
+ }
+ list[i].size = size;
+ if ((err = der_length_octet_string(size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_NULL:
+ if (inlen < 2 || in[x] != 0x05 || in[x+1] != 0x00) {
+ if (!ordered || list[i].optional) { continue; }
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+ z = 2;
+ break;
+
+ case LTC_ASN1_OBJECT_IDENTIFIER:
+ z = inlen;
+ if ((err = der_decode_object_identifier(in + x, z, data, &size)) != CRYPT_OK) {
+ if (!ordered || list[i].optional) { continue; }
+ goto LBL_ERR;
+ }
+ list[i].size = size;
+ if ((err = der_length_object_identifier(data, size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_TELETEX_STRING:
+ z = inlen;
+ if ((err = der_decode_teletex_string(in + x, z, data, &size)) != CRYPT_OK) {
+ if (!ordered || list[i].optional) { continue; }
+ goto LBL_ERR;
+ }
+ list[i].size = size;
+ if ((err = der_length_teletex_string(data, size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_IA5_STRING:
+ z = inlen;
+ if ((err = der_decode_ia5_string(in + x, z, data, &size)) != CRYPT_OK) {
+ if (!ordered || list[i].optional) { continue; }
+ goto LBL_ERR;
+ }
+ list[i].size = size;
+ if ((err = der_length_ia5_string(data, size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_PRINTABLE_STRING:
+ z = inlen;
+ if ((err = der_decode_printable_string(in + x, z, data, &size)) != CRYPT_OK) {
+ if (!ordered || list[i].optional) { continue; }
+ goto LBL_ERR;
+ }
+ list[i].size = size;
+ if ((err = der_length_printable_string(data, size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_UTF8_STRING:
+ z = inlen;
+ if ((err = der_decode_utf8_string(in + x, z, data, &size)) != CRYPT_OK) {
+ if (!ordered || list[i].optional) { continue; }
+ goto LBL_ERR;
+ }
+ list[i].size = size;
+ if ((err = der_length_utf8_string(data, size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_UTCTIME:
+ z = inlen;
+ if ((err = der_decode_utctime(in + x, &z, data)) != CRYPT_OK) {
+ if (!ordered || list[i].optional) { continue; }
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_GENERALIZEDTIME:
+ z = inlen;
+ if ((err = der_decode_generalizedtime(in + x, &z, data)) != CRYPT_OK) {
+ if (!ordered || list[i].optional) { continue; }
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_SET:
+ z = inlen;
+ if ((err = der_decode_set(in + x, z, data, size)) != CRYPT_OK) {
+ if (!ordered || list[i].optional) { continue; }
+ goto LBL_ERR;
+ }
+ if ((err = der_length_sequence(data, size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_SETOF:
+ case LTC_ASN1_SEQUENCE:
+ /* detect if we have the right type */
+ if ((type == LTC_ASN1_SETOF && (in[x] & 0x3F) != 0x31) || (type == LTC_ASN1_SEQUENCE && (in[x] & 0x3F) != 0x30)) {
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+
+ z = inlen;
+ err = der_decode_sequence_ex(in + x, z, data, size, flags);
+ if (err == CRYPT_INPUT_TOO_LONG) {
+ seq_err = CRYPT_INPUT_TOO_LONG;
+ err = CRYPT_OK;
+ }
+ if (err != CRYPT_OK) {
+ if (!ordered || list[i].optional) { continue; }
+ goto LBL_ERR;
+ }
+ if ((err = der_length_sequence(data, size, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_CUSTOM_TYPE:
+ z = inlen;
+ err = der_decode_custom_type(in + x, z, &list[i]);
+ if (err == CRYPT_INPUT_TOO_LONG) {
+ seq_err = CRYPT_INPUT_TOO_LONG;
+ err = CRYPT_OK;
+ }
+ if (err != CRYPT_OK) {
+ if (!ordered || list[i].optional) { continue; }
+ goto LBL_ERR;
+ }
+ if ((err = der_length_custom_type(&list[i], &z, NULL)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_CHOICE:
+ z = inlen;
+ if ((err = der_decode_choice(in + x, &z, data, size)) != CRYPT_OK) {
+ if (!ordered || list[i].optional) { continue; }
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_EOL:
+ err = CRYPT_INVALID_ARG;
+ goto LBL_ERR;
+ }
+ x += z;
+ inlen -= z;
+ list[i].used = 1;
+ if (!ordered) {
+ /* restart the decoder */
+ i = -1;
+ }
+ }
+
+ for (i = 0; i < (int)outlen; i++) {
+ if (list[i].used == 0 && list[i].optional == 0) {
+ err = CRYPT_INVALID_PACKET;
+ goto LBL_ERR;
+ }
+ }
+
+ if (blksize == x && seq_err == CRYPT_OK && inlen == 0) {
+ /* everything decoded and no errors in nested sequences */
+ err = CRYPT_OK;
+ } else if (blksize == x && seq_err == CRYPT_INPUT_TOO_LONG && inlen == 0) {
+ /* a sequence reported too-long input, but now we've decoded everything */
+ err = CRYPT_OK;
+ } else if (blksize != x && ((flags & LTC_DER_SEQ_STRICT) == LTC_DER_SEQ_STRICT)) {
+ err = CRYPT_INVALID_PACKET;
+ } else {
+ err = CRYPT_INPUT_TOO_LONG;
+ }
+
+LBL_ERR:
+ if (in_new != NULL) {
+ XFREE(in_new);
+ }
+ return err;
+}
+
+#endif
+
+/* ref: $Format:%D$ */
+/* git commit: $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/src/pk/asn1/der/custom_type/der_encode_custom_type.c b/src/pk/asn1/der/custom_type/der_encode_custom_type.c
new file mode 100644
index 000000000..d19774c47
--- /dev/null
+++ b/src/pk/asn1/der/custom_type/der_encode_custom_type.c
@@ -0,0 +1,238 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+
+/**
+ @file der_encode_custom_type.c
+ ASN.1 DER, encode a Custom Type, Steffen Jaeckel
+*/
+
+#ifdef LTC_DER
+
+/**
+ Encode a Custom Type
+
+ This function is a bit special compared to the others, as it requires the
+ root-ltc_asn1_list where the type is defined.
+
+ @param root The root of the list of items to encode
+ @param out [out] The destination
+ @param outlen [in/out] The size of the output
+ @return CRYPT_OK on success
+*/
+int der_encode_custom_type(const ltc_asn1_list *root,
+ unsigned char *out, unsigned long *outlen)
+{
+ int err;
+ ltc_asn1_type type;
+ const ltc_asn1_list *list;
+ unsigned long size, x, y, z, i, inlen, id_len;
+ void *data;
+
+ LTC_ARGCHK(root != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* get size of output that will be required */
+ y = 0; z = 0;
+ if ((err = der_length_custom_type(root, &y, &z)) != CRYPT_OK) return CRYPT_INVALID_ARG;
+
+ /* too big ? */
+ if (*outlen < y) {
+ *outlen = y;
+ err = CRYPT_BUFFER_OVERFLOW;
+ goto LBL_ERR;
+ }
+
+ /* get length of the identifier, so we know the offset where to start writing */
+ if ((err = der_length_asn1_identifier(root, &id_len)) != CRYPT_OK) return CRYPT_INVALID_ARG;
+ x = id_len;
+
+
+ if (root->pc == LTC_ASN1_PC_PRIMITIVE) {
+ list = root;
+ inlen = 1;
+ /* In case it's a PRIMITIVE type we encode directly to the output
+ * but leave space for a potentially longer identifier as it will
+ * simply be replaced afterwards.
+ */
+ x -= 1;
+ } else {
+ list = root->data;
+ inlen = root->size;
+ /* store length, identifier will be added later */
+ y = *outlen - x;
+ if ((err = der_encode_asn1_length(z, &out[x], &y)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ x += y;
+ }
+
+ /* store data */
+ *outlen -= x;
+ for (i = 0; i < inlen; i++) {
+ if (root->pc == LTC_ASN1_PC_PRIMITIVE) {
+ type = (ltc_asn1_type)list[i].used;
+ } else {
+ type = list[i].type;
+ }
+ size = list[i].size;
+ data = list[i].data;
+
+ if (type == LTC_ASN1_EOL) {
+ break;
+ }
+
+ switch (type) {
+ case LTC_ASN1_BOOLEAN:
+ z = *outlen;
+ if ((err = der_encode_boolean(*((int *)data), out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_INTEGER:
+ z = *outlen;
+ if ((err = der_encode_integer(data, out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_SHORT_INTEGER:
+ z = *outlen;
+ if ((err = der_encode_short_integer(*((unsigned long*)data), out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_BIT_STRING:
+ z = *outlen;
+ if ((err = der_encode_bit_string(data, size, out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_RAW_BIT_STRING:
+ z = *outlen;
+ if ((err = der_encode_raw_bit_string(data, size, out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_OCTET_STRING:
+ z = *outlen;
+ if ((err = der_encode_octet_string(data, size, out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_NULL:
+ out[x] = 0x05;
+ out[x+1] = 0x00;
+ z = 2;
+ break;
+
+ case LTC_ASN1_OBJECT_IDENTIFIER:
+ z = *outlen;
+ if ((err = der_encode_object_identifier(data, size, out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_IA5_STRING:
+ z = *outlen;
+ if ((err = der_encode_ia5_string(data, size, out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_PRINTABLE_STRING:
+ z = *outlen;
+ if ((err = der_encode_printable_string(data, size, out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_UTF8_STRING:
+ z = *outlen;
+ if ((err = der_encode_utf8_string(data, size, out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_UTCTIME:
+ z = *outlen;
+ if ((err = der_encode_utctime(data, out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_GENERALIZEDTIME:
+ z = *outlen;
+ if ((err = der_encode_generalizedtime(data, out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_SET:
+ z = *outlen;
+ if ((err = der_encode_set(data, size, out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_SETOF:
+ z = *outlen;
+ if ((err = der_encode_setof(data, size, out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_SEQUENCE:
+ z = *outlen;
+ if ((err = der_encode_sequence_ex(data, size, out + x, &z, type)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_CUSTOM_TYPE:
+ z = *outlen;
+ if ((err = der_encode_custom_type(&list[i], out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
+ case LTC_ASN1_CHOICE:
+ case LTC_ASN1_EOL:
+ case LTC_ASN1_TELETEX_STRING:
+ err = CRYPT_INVALID_ARG;
+ goto LBL_ERR;
+ }
+
+
+ x += z;
+ *outlen -= z;
+ }
+
+ if ((err = der_encode_asn1_identifier(root, out, &id_len)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ *outlen = x;
+ err = CRYPT_OK;
+
+LBL_ERR:
+ return err;
+}
+
+#endif
+
+/* ref: $Format:%D$ */
+/* git commit: $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/src/pk/asn1/der/custom_type/der_length_custom_type.c b/src/pk/asn1/der/custom_type/der_length_custom_type.c
new file mode 100644
index 000000000..aecc46476
--- /dev/null
+++ b/src/pk/asn1/der/custom_type/der_length_custom_type.c
@@ -0,0 +1,213 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_length_custom_type.c
+ ASN.1 DER, length of a custom type, Steffen Jaeckel
+*/
+
+#ifdef LTC_DER
+
+/**
+ Get the length of a DER custom type
+
+ This function is a bit special compared to the others, as it requires the
+ root-ltc_asn1_list where the type is defined.
+
+ @param root The root of the struct to encode
+ @param outlen [out] The length required in octets to store it
+ @param payloadlen [out] The length of the payload in octets
+ @return CRYPT_OK on success
+*/
+int der_length_custom_type(const ltc_asn1_list *root, unsigned long *outlen, unsigned long *payloadlen)
+{
+ int err;
+ const ltc_asn1_list *list;
+ ltc_asn1_type type;
+ unsigned long size, x, y, i, inlen, id_len;
+ void *data;
+
+ LTC_ARGCHK(root != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ /* get size of output that will be required */
+ if ((err = der_length_asn1_identifier(root, &id_len)) != CRYPT_OK) {
+ return err;
+ }
+ y = id_len;
+
+ if (root->pc == LTC_ASN1_PC_PRIMITIVE) {
+ list = root;
+ inlen = 1;
+ } else {
+ list = root->data;
+ inlen = root->size;
+ }
+ for (i = 0; i < inlen; i++) {
+ if (root->pc == LTC_ASN1_PC_PRIMITIVE) {
+ type = (ltc_asn1_type)list[i].used;
+ } else {
+ type = list[i].type;
+ }
+ size = list[i].size;
+ data = list[i].data;
+
+ if (type == LTC_ASN1_EOL) {
+ break;
+ }
+
+ /* some items may be optional during import */
+ if (!list[i].used && list[i].optional) continue;
+
+ switch (type) {
+ case LTC_ASN1_BOOLEAN:
+ if ((err = der_length_boolean(&x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_INTEGER:
+ if ((err = der_length_integer(data, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_SHORT_INTEGER:
+ if ((err = der_length_short_integer(*((unsigned long *)data), &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_BIT_STRING:
+ case LTC_ASN1_RAW_BIT_STRING:
+ if ((err = der_length_bit_string(size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_OCTET_STRING:
+ if ((err = der_length_octet_string(size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_NULL:
+ y += 2;
+ break;
+
+ case LTC_ASN1_OBJECT_IDENTIFIER:
+ if ((err = der_length_object_identifier(data, size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_IA5_STRING:
+ if ((err = der_length_ia5_string(data, size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_TELETEX_STRING:
+ if ((err = der_length_teletex_string(data, size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_PRINTABLE_STRING:
+ if ((err = der_length_printable_string(data, size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_UTCTIME:
+ if ((err = der_length_utctime(data, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_GENERALIZEDTIME:
+ if ((err = der_length_generalizedtime(data, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_UTF8_STRING:
+ if ((err = der_length_utf8_string(data, size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_CUSTOM_TYPE:
+ if ((err = der_length_custom_type(&list[i], &x, NULL)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_SET:
+ case LTC_ASN1_SETOF:
+ case LTC_ASN1_SEQUENCE:
+ if ((err = der_length_sequence(data, size, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
+ case LTC_ASN1_CHOICE:
+ case LTC_ASN1_EOL:
+ err = CRYPT_INVALID_ARG;
+ goto LBL_ERR;
+ }
+ }
+
+ if (root->pc == LTC_ASN1_PC_PRIMITIVE) {
+ /* In case it's a PRIMITIVE element we're going
+ * to only replace the identifier of the one element
+ * by the custom identifier.
+ */
+ y -= 1;
+ if (payloadlen != NULL) {
+ *payloadlen = y - id_len;
+ }
+ } else {
+ /* calc length of length */
+ if ((err = der_length_asn1_length(y, &x)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ if (payloadlen != NULL) {
+ *payloadlen = y - id_len;
+ }
+ y += x;
+ }
+
+ /* store size */
+ *outlen = y;
+
+LBL_ERR:
+ return err;
+}
+
+#endif
+
+/* ref: $Format:%D$ */
+/* git commit: $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/src/pk/asn1/der/general/der_asn1_maps.c b/src/pk/asn1/der/general/der_asn1_maps.c
new file mode 100644
index 000000000..ba9820f4e
--- /dev/null
+++ b/src/pk/asn1/der/general/der_asn1_maps.c
@@ -0,0 +1,167 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_asn1_maps.c
+ ASN.1 DER, a collection of maps to convert between different representations, Steffen Jaeckel
+*/
+
+#ifdef LTC_DER
+
+/**
+ A Map from ltc_asn1_type to the regularly used ASN.1 identifier
+*/
+const int der_asn1_type_to_identifier_map[] =
+{
+ /* 0 */
+ -1, /* LTC_ASN1_EOL, */
+ 1, /* LTC_ASN1_BOOLEAN, */
+ 2, /* LTC_ASN1_INTEGER, */
+ 2, /* LTC_ASN1_SHORT_INTEGER, */
+ 3, /* LTC_ASN1_BIT_STRING, */
+ /* 5 */
+ 4, /* LTC_ASN1_OCTET_STRING, */
+ 5, /* LTC_ASN1_NULL, */
+ 6, /* LTC_ASN1_OBJECT_IDENTIFIER, */
+ 22, /* LTC_ASN1_IA5_STRING, */
+ 19, /* LTC_ASN1_PRINTABLE_STRING, */
+ /* 10 */
+ 12, /* LTC_ASN1_UTF8_STRING, */
+ 23, /* LTC_ASN1_UTCTIME, */
+ -1, /* LTC_ASN1_CHOICE, */
+ 48, /* LTC_ASN1_SEQUENCE, */
+ 49, /* LTC_ASN1_SET, */
+ /* 15 */
+ 49, /* LTC_ASN1_SETOF, */
+ 3, /* LTC_ASN1_RAW_BIT_STRING, */
+ 20, /* LTC_ASN1_TELETEX_STRING, */
+ 24, /* LTC_ASN1_GENERALIZEDTIME, */
+ -1, /* LTC_ASN1_CUSTOM_TYPE, */
+};
+const unsigned long der_asn1_type_to_identifier_map_sz = sizeof(der_asn1_type_to_identifier_map)/sizeof(der_asn1_type_to_identifier_map[0]);
+
+/**
+ A Map from the ASN.1 Class to its string
+*/
+const char* der_asn1_class_to_string_map[] =
+{
+ "UNIVERSAL",
+ "APPLICATION",
+ "CONTEXT-SPECIFIC",
+ "PRIVATE",
+};
+const unsigned long der_asn1_class_to_string_map_sz = sizeof(der_asn1_class_to_string_map)/sizeof(der_asn1_class_to_string_map[0]);
+
+/**
+ A Map from the ASN.1 P/C-bit to its string
+*/
+const char* der_asn1_pc_to_string_map[] =
+{
+ "PRIMITIVE",
+ "CONSTRUCTED",
+};
+const unsigned long der_asn1_pc_to_string_map_sz = sizeof(der_asn1_pc_to_string_map)/sizeof(der_asn1_pc_to_string_map[0]);
+
+/**
+ A Map from the ASN.1 tag to its string
+*/
+const char* der_asn1_tag_to_string_map[] =
+{
+ "Reserved for use by the encoding rules",
+ "Boolean type",
+ "Integer type",
+ "Bitstring type",
+ "Octetstring type",
+ "Null type",
+ "Object identifier type",
+ "Object descriptor type",
+ "External type and Instance-of type",
+ "Real type",
+ "Enumerated type",
+ "Embedded-pdv type",
+ "UTF8String type",
+ "Relative object identifier type",
+ "The time type",
+ "Reserved for future editions of this Recommendation | International Standard",
+ "Sequence and Sequence-of types",
+ "Set and Set-of types",
+ "NumericString type",
+ "PrintableString type",
+ "TeletexString (T61String) type",
+ "VideotexString type",
+ "IA5String type",
+ "UTCTime type",
+ "GeneralizedTime type",
+ "GraphicString type",
+ "VisibleString (ISO646String) type",
+ "GeneralString type",
+ "UniversalString type",
+ "UnrestrictedCharacterString type",
+ "BMPString type",
+ "Date type",
+ "TimeOfDay type",
+ "DateTime type",
+ "Duration type",
+ "OID internationalized resource identifier type",
+ "Relative OID internationalized resource identifier type",
+};
+const unsigned long der_asn1_tag_to_string_map_sz = sizeof(der_asn1_tag_to_string_map)/sizeof(der_asn1_tag_to_string_map[0]);
+
+/**
+ A Map from ASN.1 Tags to ltc_asn1_type
+*/
+const ltc_asn1_type der_asn1_tag_to_type_map[] =
+{
+ /* 0 */
+ LTC_ASN1_EOL, /* Reserved for use by the encoding rules */
+ LTC_ASN1_BOOLEAN, /* Boolean type */
+ LTC_ASN1_INTEGER, /* Integer type */
+ LTC_ASN1_BIT_STRING, /* Bitstring type */
+ LTC_ASN1_OCTET_STRING, /* Octetstring type */
+ /* 5 */
+ LTC_ASN1_NULL, /* Null type */
+ LTC_ASN1_OBJECT_IDENTIFIER, /* Object identifier type */
+ LTC_ASN1_CUSTOM_TYPE, /* Object descriptor type */
+ LTC_ASN1_CUSTOM_TYPE, /* External type and Instance-of type */
+ LTC_ASN1_CUSTOM_TYPE, /* Real type */
+ /* 10 */
+ LTC_ASN1_CUSTOM_TYPE, /* Enumerated type */
+ LTC_ASN1_CUSTOM_TYPE, /* Embedded-pdv type */
+ LTC_ASN1_UTF8_STRING, /* UTF8String type */
+ LTC_ASN1_CUSTOM_TYPE, /* Relative object identifier type */
+ LTC_ASN1_CUSTOM_TYPE, /* The time type */
+ /* 15 */
+ LTC_ASN1_EOL, /* Reserved for future editions of this Recommendation | International Standard */
+ LTC_ASN1_SEQUENCE, /* Sequence and Sequence-of types */
+ LTC_ASN1_SET, /* Set and Set-of types */
+ LTC_ASN1_CUSTOM_TYPE, /* NumericString types */
+ LTC_ASN1_PRINTABLE_STRING, /* PrintableString types */
+ /* 20 */
+ LTC_ASN1_TELETEX_STRING, /* TeletexString (T61String) types */
+ LTC_ASN1_CUSTOM_TYPE, /* VideotexString types */
+ LTC_ASN1_IA5_STRING, /* IA5String types */
+ LTC_ASN1_UTCTIME, /* UTCTime types */
+ LTC_ASN1_GENERALIZEDTIME, /* GeneralizedTime types */
+ /* 25 */
+ LTC_ASN1_CUSTOM_TYPE, /* GraphicString types */
+ LTC_ASN1_CUSTOM_TYPE, /* VisibleString (ISO646String) types */
+ LTC_ASN1_CUSTOM_TYPE, /* GeneralString types */
+ LTC_ASN1_CUSTOM_TYPE, /* UniversalString types */
+ LTC_ASN1_CUSTOM_TYPE, /* UnrestrictedCharacterString types */
+ /* 30 */
+ LTC_ASN1_CUSTOM_TYPE, /* BMPString types */
+};
+const unsigned long der_asn1_tag_to_type_map_sz = sizeof(der_asn1_tag_to_type_map)/sizeof(der_asn1_tag_to_type_map[0]);
+
+#endif
+
+/* ref: $Format:%D$ */
+/* git commit: $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/src/pk/asn1/der/general/der_decode_asn1_identifier.c b/src/pk/asn1/der/general/der_decode_asn1_identifier.c
new file mode 100644
index 000000000..b4689f6aa
--- /dev/null
+++ b/src/pk/asn1/der/general/der_decode_asn1_identifier.c
@@ -0,0 +1,133 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_decode_asn1_identifier.c
+ ASN.1 DER, decode the ASN.1 Identifier, Steffen Jaeckel
+*/
+
+#ifdef LTC_DER
+/* c.f. X.680 & X.690, some decisions backed by X.690 ch. 10.2 */
+static const unsigned char tag_constructed_map[] =
+{
+ /* 0 */
+ 255,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ /* 5 */
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ /* 10 */
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ /* 15 */
+ 255,
+ LTC_ASN1_PC_CONSTRUCTED,
+ LTC_ASN1_PC_CONSTRUCTED,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ /* 20 */
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ /* 25 */
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+};
+ static const unsigned long tag_constructed_map_sz = sizeof(tag_constructed_map)/sizeof(tag_constructed_map[0]);
+
+/**
+ Decode the ASN.1 Identifier
+ @param id Where to store the decoded Identifier
+ @param in Where to read the Identifier from
+ @param inlen [in/out] The size of in available/read
+ @return CRYPT_OK if successful
+*/
+int der_decode_asn1_identifier(const unsigned char *in, unsigned long *inlen, ltc_asn1_list *id)
+{
+ ulong64 tmp;
+ unsigned long tag_len;
+ int err;
+
+ LTC_ARGCHK(id != NULL);
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(inlen != NULL);
+
+ if (*inlen == 0) {
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ tag_len = 1;
+ id->class = (in[0] >> 6) & 0x3;
+ id->pc = (in[0] >> 5) & 0x1;
+ id->tag = in[0] & 0x1f;
+
+ err = CRYPT_OK;
+ if (id->tag == 0x1f) {
+ id->tag = 0;
+ do {
+ if (*inlen < tag_len) {
+ /* break the loop and trigger the BOF error-code */
+ tmp = 0xff;
+ break;
+ }
+ id->tag <<= 7;
+ id->tag |= in[tag_len] & 0x7f;
+ tmp = in[tag_len] & 0x80;
+ tag_len++;
+ } while ((tmp != 0) && (tag_len < 10));
+
+ if (tmp != 0) {
+ err = CRYPT_BUFFER_OVERFLOW;
+ } else if (id->tag < 0x1f) {
+ err = CRYPT_PK_ASN1_ERROR;
+ }
+ }
+
+ if (err != CRYPT_OK) {
+ id->pc = 0;
+ id->class = 0;
+ id->tag = 0;
+ } else {
+ *inlen = tag_len;
+ if ((id->class == LTC_ASN1_CL_UNIVERSAL) &&
+ (id->tag < der_asn1_tag_to_type_map_sz) &&
+ (id->tag < tag_constructed_map_sz) &&
+ (id->pc == tag_constructed_map[id->tag])) {
+ id->type = der_asn1_tag_to_type_map[id->tag];
+ } else {
+ if ((id->class == LTC_ASN1_CL_UNIVERSAL) && (id->tag == 0)) {
+ id->type = LTC_ASN1_EOL;
+ } else {
+ id->type = LTC_ASN1_CUSTOM_TYPE;
+ }
+ }
+ }
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* ref: $Format:%D$ */
+/* git commit: $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/src/pk/asn1/der/general/der_decode_asn1_length.c b/src/pk/asn1/der/general/der_decode_asn1_length.c
new file mode 100644
index 000000000..0e1bc6c2b
--- /dev/null
+++ b/src/pk/asn1/der/general/der_decode_asn1_length.c
@@ -0,0 +1,67 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_decode_asn1_length.c
+ ASN.1 DER, decode the ASN.1 Length field, Steffen Jaeckel
+*/
+
+#ifdef LTC_DER
+/**
+ Decode the ASN.1 Length field
+ @param in Where to read the length field from
+ @param inlen [in/out] The size of in available/read
+ @param outlen [out] The decoded ASN.1 length
+ @return CRYPT_OK if successful
+*/
+int der_decode_asn1_length(const unsigned char *in, unsigned long *inlen, unsigned long *outlen)
+{
+ unsigned long real_len, decoded_len, offset, i;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(inlen != NULL);
+
+ if (*inlen < 1) {
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ real_len = in[0];
+
+ if (real_len < 128) {
+ decoded_len = real_len;
+ offset = 1;
+ } else {
+ real_len &= 0x7F;
+ if (real_len == 0) {
+ return CRYPT_PK_ASN1_ERROR;
+ } else if (real_len > sizeof(decoded_len)) {
+ return CRYPT_OVERFLOW;
+ } else if (real_len > (*inlen - 1)) {
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+ decoded_len = 0;
+ offset = 1 + real_len;
+ for (i = 0; i < real_len; i++) {
+ decoded_len = (decoded_len << 8) | in[1 + i];
+ }
+ }
+
+ if (outlen != NULL) *outlen = decoded_len;
+ if (decoded_len > (*inlen - offset)) return CRYPT_OVERFLOW;
+ *inlen = offset;
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* ref: $Format:%D$ */
+/* git commit: $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/src/pk/asn1/der/general/der_encode_asn1_identifier.c b/src/pk/asn1/der/general/der_encode_asn1_identifier.c
new file mode 100644
index 000000000..95fdd8463
--- /dev/null
+++ b/src/pk/asn1/der/general/der_encode_asn1_identifier.c
@@ -0,0 +1,97 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_encode_asn1_identifier.c
+ ASN.1 DER, encode the ASN.1 Identifier, Steffen Jaeckel
+*/
+
+#ifdef LTC_DER
+/**
+ Encode the ASN.1 Identifier
+ @param id The ASN.1 Identifer to encode
+ @param out Where to write the identifier to
+ @param outlen [in/out] The size of out available/written
+ @return CRYPT_OK if successful
+*/
+int der_encode_asn1_identifier(const ltc_asn1_list *id, unsigned char *out, unsigned long *outlen)
+{
+ ulong64 tmp;
+ unsigned long tag_len;
+
+ LTC_ARGCHK(id != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ if (id->type != LTC_ASN1_CUSTOM_TYPE) {
+ if (id->type >= der_asn1_type_to_identifier_map_sz) {
+ return CRYPT_INVALID_ARG;
+ }
+ if (der_asn1_type_to_identifier_map[id->type] == -1) {
+ return CRYPT_INVALID_ARG;
+ }
+ if (out != NULL) {
+ *out = der_asn1_type_to_identifier_map[id->type];
+ }
+ *outlen = 1;
+ return CRYPT_OK;
+ } else {
+ if (id->class < LTC_ASN1_CL_UNIVERSAL || id->class > LTC_ASN1_CL_PRIVATE) {
+ return CRYPT_INVALID_ARG;
+ }
+ if (id->pc < LTC_ASN1_PC_PRIMITIVE || id->pc > LTC_ASN1_PC_CONSTRUCTED) {
+ return CRYPT_INVALID_ARG;
+ }
+ if (id->tag > (ULONG_MAX >> (8 + 7))) {
+ return CRYPT_INVALID_ARG;
+ }
+ }
+
+ if (out != NULL) {
+ if (*outlen < 1) {
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ out[0] = id->class << 6 | id->pc << 5;
+ }
+
+ if (id->tag < 0x1f) {
+ if (out != NULL) {
+ out[0] |= id->tag & 0x1f;
+ }
+ *outlen = 1;
+ } else {
+ tag_len = 0;
+ tmp = id->tag;
+ do {
+ tag_len++;
+ tmp >>= 7;
+ } while (tmp);
+
+ if (out != NULL) {
+ if (*outlen < tag_len + 1) {
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+ out[0] |= 0x1f;
+ for (tmp = 1; tmp <= tag_len; ++tmp) {
+ out[tmp] = ((id->tag >> (7 * (tag_len - tmp))) & 0x7f) | 0x80;
+ }
+ out[tag_len] &= ~0x80;
+ }
+ *outlen = tag_len + 1;
+ }
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* ref: $Format:%D$ */
+/* git commit: $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/src/pk/asn1/der/general/der_encode_asn1_length.c b/src/pk/asn1/der/general/der_encode_asn1_length.c
new file mode 100644
index 000000000..456503ca2
--- /dev/null
+++ b/src/pk/asn1/der/general/der_encode_asn1_length.c
@@ -0,0 +1,121 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_encode_asn1_length.c
+ ASN.1 DER, encode the ASN.1 length field, Steffen Jaeckel
+*/
+
+#ifdef LTC_DER
+/**
+ Encode the ASN.1 length field
+ @param len The length to encode
+ @param out Where to write the length field to
+ @param outlen [in/out] The size of out available/written
+ @return CRYPT_OK if successful
+*/
+int der_encode_asn1_length(unsigned long len, unsigned char *out, unsigned long *outlen)
+{
+ unsigned long x, y;
+
+ LTC_ARGCHK(outlen != NULL);
+
+ x = len;
+ y = 0;
+
+ while(x != 0) {
+ y++;
+ x >>= 8;
+ }
+ if (y == 0) {
+ return CRYPT_PK_ASN1_ERROR;
+ }
+
+ if (out == NULL) {
+ if (len < 128) {
+ x = y;
+ } else {
+ x = y + 1;
+ }
+ } else {
+ if (*outlen < y) {
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+ x = 0;
+ if (len < 128) {
+ out[x++] = (unsigned char)len;
+ } else if (len <= 0xffUL) {
+ out[x++] = 0x81;
+ out[x++] = (unsigned char)len;
+ } else if (len <= 0xffffUL) {
+ out[x++] = 0x82;
+ out[x++] = (unsigned char)((len>>8UL)&255);
+ out[x++] = (unsigned char)(len&255);
+ } else if (len <= 0xffffffUL) {
+ out[x++] = 0x83;
+ out[x++] = (unsigned char)((len>>16UL)&255);
+ out[x++] = (unsigned char)((len>>8UL)&255);
+ out[x++] = (unsigned char)(len&255);
+ } else if (len <= 0xffffffffUL) {
+ out[x++] = 0x84;
+ out[x++] = (unsigned char)((len>>24UL)&255);
+ out[x++] = (unsigned char)((len>>16UL)&255);
+ out[x++] = (unsigned char)((len>>8UL)&255);
+ out[x++] = (unsigned char)(len&255);
+ #if ULONG_MAX == ULLONG_MAX
+ } else if (len <= 0xffffffffffULL) {
+ out[x++] = 0x85;
+ out[x++] = (unsigned char)((len>>32ULL)&255);
+ out[x++] = (unsigned char)((len>>24ULL)&255);
+ out[x++] = (unsigned char)((len>>16ULL)&255);
+ out[x++] = (unsigned char)((len>>8ULL)&255);
+ out[x++] = (unsigned char)(len&255);
+ } else if (len <= 0xffffffffffffULL) {
+ out[x++] = 0x86;
+ out[x++] = (unsigned char)((len>>40ULL)&255);
+ out[x++] = (unsigned char)((len>>32ULL)&255);
+ out[x++] = (unsigned char)((len>>24ULL)&255);
+ out[x++] = (unsigned char)((len>>16ULL)&255);
+ out[x++] = (unsigned char)((len>>8ULL)&255);
+ out[x++] = (unsigned char)(len&255);
+ } else if (len <= 0xffffffffffffffULL) {
+ out[x++] = 0x87;
+ out[x++] = (unsigned char)((len>>48ULL)&255);
+ out[x++] = (unsigned char)((len>>40ULL)&255);
+ out[x++] = (unsigned char)((len>>32ULL)&255);
+ out[x++] = (unsigned char)((len>>24ULL)&255);
+ out[x++] = (unsigned char)((len>>16ULL)&255);
+ out[x++] = (unsigned char)((len>>8ULL)&255);
+ out[x++] = (unsigned char)(len&255);
+ } else if (len <= 0xffffffffffffffffULL) {
+ out[x++] = 0x88;
+ out[x++] = (unsigned char)((len>>56ULL)&255);
+ out[x++] = (unsigned char)((len>>48ULL)&255);
+ out[x++] = (unsigned char)((len>>40ULL)&255);
+ out[x++] = (unsigned char)((len>>32ULL)&255);
+ out[x++] = (unsigned char)((len>>24ULL)&255);
+ out[x++] = (unsigned char)((len>>16ULL)&255);
+ out[x++] = (unsigned char)((len>>8ULL)&255);
+ out[x++] = (unsigned char)(len&255);
+ #endif
+ } else {
+ return CRYPT_INPUT_TOO_LONG;
+ }
+ }
+ *outlen = x;
+
+ return CRYPT_OK;
+}
+
+#endif
+
+/* ref: $Format:%D$ */
+/* git commit: $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/src/pk/asn1/der/general/der_length_asn1_identifier.c b/src/pk/asn1/der/general/der_length_asn1_identifier.c
new file mode 100644
index 000000000..40e76f028
--- /dev/null
+++ b/src/pk/asn1/der/general/der_length_asn1_identifier.c
@@ -0,0 +1,33 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_length_asn1_identifier.c
+ ASN.1 DER, determine the length when encoding the ASN.1 Identifier, Steffen Jaeckel
+*/
+
+#ifdef LTC_DER
+/**
+ Determine the length required when encoding the ASN.1 Identifier
+ @param id The ASN.1 identifier to encode
+ @param idlen [out] The required length to encode list
+ @return CRYPT_OK if successful
+*/
+
+int der_length_asn1_identifier(const ltc_asn1_list *id, unsigned long *idlen)
+{
+ return der_encode_asn1_identifier(id, NULL, idlen);
+}
+
+#endif
+
+/* ref: $Format:%D$ */
+/* git commit: $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/src/pk/asn1/der/general/der_length_asn1_length.c b/src/pk/asn1/der/general/der_length_asn1_length.c
new file mode 100644
index 000000000..1271e1cbc
--- /dev/null
+++ b/src/pk/asn1/der/general/der_length_asn1_length.c
@@ -0,0 +1,32 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+ @file der_length_asn1_length.c
+ ASN.1 DER, determine the length of the ASN.1 length field, Steffen Jaeckel
+*/
+
+#ifdef LTC_DER
+/**
+ Determine the length required to encode len in the ASN.1 length field
+ @param len The length to encode
+ @param outlen [out] The length that's required to store len
+ @return CRYPT_OK if successful
+*/
+int der_length_asn1_length(unsigned long len, unsigned long *outlen)
+{
+ return der_encode_asn1_length(len, NULL, outlen);
+}
+
+#endif
+
+/* ref: $Format:%D$ */
+/* git commit: $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/src/pk/asn1/der/ia5/der_decode_ia5_string.c b/src/pk/asn1/der/ia5/der_decode_ia5_string.c
index c3472519e..15e90f88a 100644
--- a/src/pk/asn1/der/ia5/der_decode_ia5_string.c
+++ b/src/pk/asn1/der/ia5/der_decode_ia5_string.c
@@ -28,7 +28,7 @@ int der_decode_ia5_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
unsigned long x, y, len;
- int t;
+ int t, err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
@@ -45,23 +45,12 @@ int der_decode_ia5_string(const unsigned char *in, unsigned long inlen,
}
x = 1;
- /* decode the length */
- if (in[x] & 0x80) {
- /* valid # of bytes in length are 1,2,3 */
- y = in[x] & 0x7F;
- if ((y == 0) || (y > 3) || ((x + y) > inlen)) {
- return CRYPT_INVALID_PACKET;
- }
-
- /* read the length in */
- len = 0;
- ++x;
- while (y--) {
- len = (len << 8) | in[x++];
- }
- } else {
- len = in[x++] & 0x7F;
+ /* get the length of the data */
+ y = inlen - x;
+ if ((err = der_decode_asn1_length(in + x, &y, &len)) != CRYPT_OK) {
+ return err;
}
+ x += y;
/* is it too long? */
if (len > *outlen) {
@@ -69,7 +58,7 @@ int der_decode_ia5_string(const unsigned char *in, unsigned long inlen,
return CRYPT_BUFFER_OVERFLOW;
}
- if (len + x > inlen) {
+ if (len > (inlen - x)) {
return CRYPT_INVALID_PACKET;
}
diff --git a/src/pk/asn1/der/ia5/der_encode_ia5_string.c b/src/pk/asn1/der/ia5/der_encode_ia5_string.c
index 18b926eac..fee1c703e 100644
--- a/src/pk/asn1/der/ia5/der_encode_ia5_string.c
+++ b/src/pk/asn1/der/ia5/der_encode_ia5_string.c
@@ -47,23 +47,11 @@ int der_encode_ia5_string(const unsigned char *in, unsigned long inlen,
/* encode the header+len */
x = 0;
out[x++] = 0x16;
- if (inlen < 128) {
- out[x++] = (unsigned char)inlen;
- } else if (inlen < 256) {
- out[x++] = 0x81;
- out[x++] = (unsigned char)inlen;
- } else if (inlen < 65536UL) {
- out[x++] = 0x82;
- out[x++] = (unsigned char)((inlen>>8)&255);
- out[x++] = (unsigned char)(inlen&255);
- } else if (inlen < 16777216UL) {
- out[x++] = 0x83;
- out[x++] = (unsigned char)((inlen>>16)&255);
- out[x++] = (unsigned char)((inlen>>8)&255);
- out[x++] = (unsigned char)(inlen&255);
- } else {
- return CRYPT_INVALID_ARG;
+ len = *outlen - x;
+ if ((err = der_encode_asn1_length(inlen, out + x, &len)) != CRYPT_OK) {
+ return err;
}
+ x += len;
/* store octets */
for (y = 0; y < inlen; y++) {
diff --git a/src/pk/asn1/der/ia5/der_length_ia5_string.c b/src/pk/asn1/der/ia5/der_length_ia5_string.c
index 5f1a78d1e..422c4d337 100644
--- a/src/pk/asn1/der/ia5/der_length_ia5_string.c
+++ b/src/pk/asn1/der/ia5/der_length_ia5_string.c
@@ -154,6 +154,7 @@ int der_ia5_value_decode(int v)
int der_length_ia5_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen)
{
unsigned long x;
+ int err;
LTC_ARGCHK(outlen != NULL);
LTC_ARGCHK(octets != NULL);
@@ -165,21 +166,10 @@ int der_length_ia5_string(const unsigned char *octets, unsigned long noctets, un
}
}
- if (noctets < 128) {
- /* 16 LL DD DD DD ... */
- *outlen = 2 + noctets;
- } else if (noctets < 256) {
- /* 16 81 LL DD DD DD ... */
- *outlen = 3 + noctets;
- } else if (noctets < 65536UL) {
- /* 16 82 LL LL DD DD DD ... */
- *outlen = 4 + noctets;
- } else if (noctets < 16777216UL) {
- /* 16 83 LL LL LL DD DD DD ... */
- *outlen = 5 + noctets;
- } else {
- return CRYPT_INVALID_ARG;
+ if ((err = der_length_asn1_length(noctets, &x)) != CRYPT_OK) {
+ return err;
}
+ *outlen = 1 + x + noctets;
return CRYPT_OK;
}
diff --git a/src/pk/asn1/der/integer/der_decode_integer.c b/src/pk/asn1/der/integer/der_decode_integer.c
index 88cf93f32..e5c5c122b 100644
--- a/src/pk/asn1/der/integer/der_decode_integer.c
+++ b/src/pk/asn1/der/integer/der_decode_integer.c
@@ -25,7 +25,7 @@
*/
int der_decode_integer(const unsigned char *in, unsigned long inlen, void *num)
{
- unsigned long x, y, z;
+ unsigned long x, y;
int err;
LTC_ARGCHK(num != NULL);
@@ -42,45 +42,15 @@ int der_decode_integer(const unsigned char *in, unsigned long inlen, void *num)
return CRYPT_INVALID_PACKET;
}
- /* now decode the len stuff */
- z = in[x++];
-
- if ((z & 0x80) == 0x00) {
- /* short form */
-
- /* will it overflow? */
- if (x + z > inlen) {
- return CRYPT_INVALID_PACKET;
- }
-
- /* no so read it */
- if ((err = mp_read_unsigned_bin(num, (unsigned char *)in + x, z)) != CRYPT_OK) {
- return err;
- }
- } else {
- /* long form */
- z &= 0x7F;
-
- /* will number of length bytes overflow? (or > 4) */
- if (((x + z) > inlen) || (z > 4) || (z == 0)) {
- return CRYPT_INVALID_PACKET;
- }
-
- /* now read it in */
- y = 0;
- while (z--) {
- y = ((unsigned long)(in[x++])) | (y << 8);
- }
-
- /* now will reading y bytes overrun? */
- if ((x + y) > inlen) {
- return CRYPT_INVALID_PACKET;
- }
+ /* get the length of the data */
+ inlen -= x;
+ if ((err = der_decode_asn1_length(in + x, &inlen, &y)) != CRYPT_OK) {
+ return err;
+ }
+ x += inlen;
- /* no so read it */
- if ((err = mp_read_unsigned_bin(num, (unsigned char *)in + x, y)) != CRYPT_OK) {
- return err;
- }
+ if ((err = mp_read_unsigned_bin(num, (unsigned char *)in + x, y)) != CRYPT_OK) {
+ return err;
}
/* see if it's negative */
diff --git a/src/pk/asn1/der/integer/der_encode_integer.c b/src/pk/asn1/der/integer/der_encode_integer.c
index a8bada558..3bd959320 100644
--- a/src/pk/asn1/der/integer/der_encode_integer.c
+++ b/src/pk/asn1/der/integer/der_encode_integer.c
@@ -26,7 +26,7 @@
*/
int der_encode_integer(void *num, unsigned char *out, unsigned long *outlen)
{
- unsigned long tmplen, y;
+ unsigned long tmplen, y, len;
int err, leading_zero;
LTC_ARGCHK(num != NULL);
@@ -63,24 +63,11 @@ int der_encode_integer(void *num, unsigned char *out, unsigned long *outlen)
/* now store initial data */
*out++ = 0x02;
- if (y < 128) {
- /* short form */
- *out++ = (unsigned char)y;
- } else if (y < 256) {
- *out++ = 0x81;
- *out++ = (unsigned char)y;
- } else if (y < 65536UL) {
- *out++ = 0x82;
- *out++ = (unsigned char)((y>>8)&255);
- *out++ = (unsigned char)y;
- } else if (y < 16777216UL) {
- *out++ = 0x83;
- *out++ = (unsigned char)((y>>16)&255);
- *out++ = (unsigned char)((y>>8)&255);
- *out++ = (unsigned char)y;
- } else {
- return CRYPT_INVALID_ARG;
+ len = *outlen - 1;
+ if ((err = der_encode_asn1_length(y, out, &len)) != CRYPT_OK) {
+ return err;
}
+ out += len;
/* now store msbyte of zero if num is non-zero */
if (leading_zero) {
diff --git a/src/pk/asn1/der/integer/der_length_integer.c b/src/pk/asn1/der/integer/der_length_integer.c
index 753ef0e09..60daffa7b 100644
--- a/src/pk/asn1/der/integer/der_length_integer.c
+++ b/src/pk/asn1/der/integer/der_length_integer.c
@@ -24,7 +24,7 @@
int der_length_integer(void *num, unsigned long *outlen)
{
unsigned long z, len;
- int leading_zero;
+ int leading_zero, err;
LTC_ARGCHK(num != NULL);
LTC_ARGCHK(outlen != NULL);
@@ -40,35 +40,21 @@ int der_length_integer(void *num, unsigned long *outlen)
}
/* size for bignum */
- z = len = leading_zero + mp_unsigned_bin_size(num);
+ len = leading_zero + mp_unsigned_bin_size(num);
} else {
/* it's negative */
/* find power of 2 that is a multiple of eight and greater than count bits */
z = mp_count_bits(num);
z = z + (8 - (z & 7));
if (((mp_cnt_lsb(num)+1)==mp_count_bits(num)) && ((mp_count_bits(num)&7)==0)) --z;
- len = z = z >> 3;
+ len = z >> 3;
}
- /* now we need a length */
- if (z < 128) {
- /* short form */
- ++len;
- } else {
- /* long form (relies on z != 0), assumes length bytes < 128 */
- ++len;
-
- while (z) {
- ++len;
- z >>= 8;
- }
+ if ((err = der_length_asn1_length(len, &z)) != CRYPT_OK) {
+ return err;
}
+ *outlen = 1 + z + len;
- /* we need a 0x02 to indicate it's INTEGER */
- ++len;
-
- /* return length */
- *outlen = len;
return CRYPT_OK;
}
diff --git a/src/pk/asn1/der/object_identifier/der_decode_object_identifier.c b/src/pk/asn1/der/object_identifier/der_decode_object_identifier.c
index 75bc127cd..48a954730 100644
--- a/src/pk/asn1/der/object_identifier/der_decode_object_identifier.c
+++ b/src/pk/asn1/der/object_identifier/der_decode_object_identifier.c
@@ -49,21 +49,14 @@ int der_decode_object_identifier(const unsigned char *in, unsigned long inle
return CRYPT_INVALID_PACKET;
}
- /* get the length */
- if (in[x] < 128) {
- len = in[x++];
- } else {
- if (in[x] < 0x81 || in[x] > 0x82) {
- return CRYPT_INVALID_PACKET;
- }
- y = in[x++] & 0x7F;
- len = 0;
- while (y--) {
- len = (len << 8) | (unsigned long)in[x++];
- }
+ /* get the length of the data */
+ y = inlen - x;
+ if ((err = der_decode_asn1_length(in + x, &y, &len)) != CRYPT_OK) {
+ return err;
}
+ x += y;
- if (len < 1 || (len + x) > inlen) {
+ if ((len == 0) || (len > (inlen - x))) {
return CRYPT_INVALID_PACKET;
}
diff --git a/src/pk/asn1/der/object_identifier/der_encode_object_identifier.c b/src/pk/asn1/der/object_identifier/der_encode_object_identifier.c
index b1ce62c9a..4b397b644 100644
--- a/src/pk/asn1/der/object_identifier/der_encode_object_identifier.c
+++ b/src/pk/asn1/der/object_identifier/der_encode_object_identifier.c
@@ -55,18 +55,11 @@ int der_encode_object_identifier(unsigned long *words, unsigned long nwords,
/* store header + length */
x = 0;
out[x++] = 0x06;
- if (z < 128) {
- out[x++] = (unsigned char)z;
- } else if (z < 256) {
- out[x++] = 0x81;
- out[x++] = (unsigned char)z;
- } else if (z < 65536UL) {
- out[x++] = 0x82;
- out[x++] = (unsigned char)((z>>8)&255);
- out[x++] = (unsigned char)(z&255);
- } else {
- return CRYPT_INVALID_ARG;
+ y = *outlen - x;
+ if ((err = der_encode_asn1_length(z, out + x, &y)) != CRYPT_OK) {
+ return err;
}
+ x += y;
/* store first byte */
wordbuf = words[0] * 40 + words[1];
diff --git a/src/pk/asn1/der/octet/der_decode_octet_string.c b/src/pk/asn1/der/octet/der_decode_octet_string.c
index 02859dca5..a9b3cdc56 100644
--- a/src/pk/asn1/der/octet/der_decode_octet_string.c
+++ b/src/pk/asn1/der/octet/der_decode_octet_string.c
@@ -28,6 +28,7 @@ int der_decode_octet_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
unsigned long x, y, len;
+ int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
@@ -44,23 +45,12 @@ int der_decode_octet_string(const unsigned char *in, unsigned long inlen,
}
x = 1;
- /* decode the length */
- if (in[x] & 0x80) {
- /* valid # of bytes in length are 1,2,3 */
- y = in[x] & 0x7F;
- if ((y == 0) || (y > 3) || ((x + y) > inlen)) {
- return CRYPT_INVALID_PACKET;
- }
-
- /* read the length in */
- len = 0;
- ++x;
- while (y--) {
- len = (len << 8) | in[x++];
- }
- } else {
- len = in[x++] & 0x7F;
+ /* get the length of the data */
+ y = inlen - x;
+ if ((err = der_decode_asn1_length(in + x, &y, &len)) != CRYPT_OK) {
+ return err;
}
+ x += y;
/* is it too long? */
if (len > *outlen) {
@@ -68,7 +58,7 @@ int der_decode_octet_string(const unsigned char *in, unsigned long inlen,
return CRYPT_BUFFER_OVERFLOW;
}
- if (len + x > inlen) {
+ if (len > (inlen - x)) {
return CRYPT_INVALID_PACKET;
}
diff --git a/src/pk/asn1/der/octet/der_encode_octet_string.c b/src/pk/asn1/der/octet/der_encode_octet_string.c
index 9c9d1a656..fd79c6732 100644
--- a/src/pk/asn1/der/octet/der_encode_octet_string.c
+++ b/src/pk/asn1/der/octet/der_encode_octet_string.c
@@ -48,23 +48,11 @@ int der_encode_octet_string(const unsigned char *in, unsigned long inlen,
/* encode the header+len */
x = 0;
out[x++] = 0x04;
- if (inlen < 128) {
- out[x++] = (unsigned char)inlen;
- } else if (inlen < 256) {
- out[x++] = 0x81;
- out[x++] = (unsigned char)inlen;
- } else if (inlen < 65536UL) {
- out[x++] = 0x82;
- out[x++] = (unsigned char)((inlen>>8)&255);
- out[x++] = (unsigned char)(inlen&255);
- } else if (inlen < 16777216UL) {
- out[x++] = 0x83;
- out[x++] = (unsigned char)((inlen>>16)&255);
- out[x++] = (unsigned char)((inlen>>8)&255);
- out[x++] = (unsigned char)(inlen&255);
- } else {
- return CRYPT_INVALID_ARG;
+ len = *outlen - x;
+ if ((err = der_encode_asn1_length(inlen, out + x, &len)) != CRYPT_OK) {
+ return err;
}
+ x += len;
/* store octets */
for (y = 0; y < inlen; y++) {
diff --git a/src/pk/asn1/der/octet/der_length_octet_string.c b/src/pk/asn1/der/octet/der_length_octet_string.c
index 10c9e892a..9e5386a3f 100644
--- a/src/pk/asn1/der/octet/der_length_octet_string.c
+++ b/src/pk/asn1/der/octet/der_length_octet_string.c
@@ -22,23 +22,15 @@
*/
int der_length_octet_string(unsigned long noctets, unsigned long *outlen)
{
+ unsigned long x;
+ int err;
+
LTC_ARGCHK(outlen != NULL);
- if (noctets < 128) {
- /* 04 LL DD DD DD ... */
- *outlen = 2 + noctets;
- } else if (noctets < 256) {
- /* 04 81 LL DD DD DD ... */
- *outlen = 3 + noctets;
- } else if (noctets < 65536UL) {
- /* 04 82 LL LL DD DD DD ... */
- *outlen = 4 + noctets;
- } else if (noctets < 16777216UL) {
- /* 04 83 LL LL LL DD DD DD ... */
- *outlen = 5 + noctets;
- } else {
- return CRYPT_INVALID_ARG;
+ if ((err = der_length_asn1_length(noctets, &x)) != CRYPT_OK) {
+ return err;
}
+ *outlen = 1 + x + noctets;
return CRYPT_OK;
}
diff --git a/src/pk/asn1/der/printable_string/der_decode_printable_string.c b/src/pk/asn1/der/printable_string/der_decode_printable_string.c
index 694742921..1ec9e3c71 100644
--- a/src/pk/asn1/der/printable_string/der_decode_printable_string.c
+++ b/src/pk/asn1/der/printable_string/der_decode_printable_string.c
@@ -28,7 +28,7 @@ int der_decode_printable_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
unsigned long x, y, len;
- int t;
+ int t, err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
@@ -45,23 +45,12 @@ int der_decode_printable_string(const unsigned char *in, unsigned long inlen,
}
x = 1;
- /* decode the length */
- if (in[x] & 0x80) {
- /* valid # of bytes in length are 1,2,3 */
- y = in[x] & 0x7F;
- if ((y == 0) || (y > 3) || ((x + y) > inlen)) {
- return CRYPT_INVALID_PACKET;
- }
-
- /* read the length in */
- len = 0;
- ++x;
- while (y--) {
- len = (len << 8) | in[x++];
- }
- } else {
- len = in[x++] & 0x7F;
+ /* get the length of the data */
+ y = inlen - x;
+ if ((err = der_decode_asn1_length(in + x, &y, &len)) != CRYPT_OK) {
+ return err;
}
+ x += y;
/* is it too long? */
if (len > *outlen) {
@@ -69,7 +58,7 @@ int der_decode_printable_string(const unsigned char *in, unsigned long inlen,
return CRYPT_BUFFER_OVERFLOW;
}
- if (len + x > inlen) {
+ if (len > (inlen - x)) {
return CRYPT_INVALID_PACKET;
}
diff --git a/src/pk/asn1/der/printable_string/der_encode_printable_string.c b/src/pk/asn1/der/printable_string/der_encode_printable_string.c
index ee54e48ff..bd5939167 100644
--- a/src/pk/asn1/der/printable_string/der_encode_printable_string.c
+++ b/src/pk/asn1/der/printable_string/der_encode_printable_string.c
@@ -47,23 +47,11 @@ int der_encode_printable_string(const unsigned char *in, unsigned long inlen,
/* encode the header+len */
x = 0;
out[x++] = 0x13;
- if (inlen < 128) {
- out[x++] = (unsigned char)inlen;
- } else if (inlen < 256) {
- out[x++] = 0x81;
- out[x++] = (unsigned char)inlen;
- } else if (inlen < 65536UL) {
- out[x++] = 0x82;
- out[x++] = (unsigned char)((inlen>>8)&255);
- out[x++] = (unsigned char)(inlen&255);
- } else if (inlen < 16777216UL) {
- out[x++] = 0x83;
- out[x++] = (unsigned char)((inlen>>16)&255);
- out[x++] = (unsigned char)((inlen>>8)&255);
- out[x++] = (unsigned char)(inlen&255);
- } else {
- return CRYPT_INVALID_ARG;
+ len = *outlen - x;
+ if ((err = der_encode_asn1_length(inlen, out + x, &len)) != CRYPT_OK) {
+ return err;
}
+ x += len;
/* store octets */
for (y = 0; y < inlen; y++) {
diff --git a/src/pk/asn1/der/printable_string/der_length_printable_string.c b/src/pk/asn1/der/printable_string/der_length_printable_string.c
index 40f0beb42..b6eb85023 100644
--- a/src/pk/asn1/der/printable_string/der_length_printable_string.c
+++ b/src/pk/asn1/der/printable_string/der_length_printable_string.c
@@ -126,6 +126,7 @@ int der_printable_value_decode(int v)
int der_length_printable_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen)
{
unsigned long x;
+ int err;
LTC_ARGCHK(outlen != NULL);
LTC_ARGCHK(octets != NULL);
@@ -137,21 +138,10 @@ int der_length_printable_string(const unsigned char *octets, unsigned long nocte
}
}
- if (noctets < 128) {
- /* 16 LL DD DD DD ... */
- *outlen = 2 + noctets;
- } else if (noctets < 256) {
- /* 16 81 LL DD DD DD ... */
- *outlen = 3 + noctets;
- } else if (noctets < 65536UL) {
- /* 16 82 LL LL DD DD DD ... */
- *outlen = 4 + noctets;
- } else if (noctets < 16777216UL) {
- /* 16 83 LL LL LL DD DD DD ... */
- *outlen = 5 + noctets;
- } else {
- return CRYPT_INVALID_ARG;
+ if ((err = der_length_asn1_length(noctets, &x)) != CRYPT_OK) {
+ return err;
}
+ *outlen = 1 + x + noctets;
return CRYPT_OK;
}
diff --git a/src/pk/asn1/der/sequence/der_decode_sequence_ex.c b/src/pk/asn1/der/sequence/der_decode_sequence_ex.c
index b820c68ab..10cfd218e 100644
--- a/src/pk/asn1/der/sequence/der_decode_sequence_ex.c
+++ b/src/pk/asn1/der/sequence/der_decode_sequence_ex.c
@@ -22,303 +22,13 @@
@param inlen The size of the input
@param list The list of items to decode
@param outlen The number of items in the list
- @param ordered Search an unordeded or ordered list
+ @param flags c.f. enum ltc_der_seq
@return CRYPT_OK on success
*/
int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen,
- ltc_asn1_list *list, unsigned long outlen, int ordered)
+ ltc_asn1_list *list, unsigned long outlen, unsigned int flags)
{
- int err, i;
- ltc_asn1_type type;
- unsigned long size, x, y, z, blksize;
- void *data;
-
- LTC_ARGCHK(in != NULL);
- LTC_ARGCHK(list != NULL);
-
- /* get blk size */
- if (inlen < 2) {
- return CRYPT_INVALID_PACKET;
- }
-
- /* sequence type? We allow 0x30 SEQUENCE and 0x31 SET since fundamentally they're the same structure */
- x = 0;
- if (in[x] != 0x30 && in[x] != 0x31) {
- return CRYPT_INVALID_PACKET;
- }
- ++x;
-
- /* check if the msb is set, which signals that the
- * 7 lsb bits represent the number of bytes of the length
- */
- if (in[x] < 128) {
- blksize = in[x++];
- } else {
- if (in[x] < 0x81 || in[x] > 0x83) {
- return CRYPT_INVALID_PACKET;
- }
- y = in[x++] & 0x7F;
-
- /* would reading the len bytes overrun? */
- if (x + y > inlen) {
- return CRYPT_INVALID_PACKET;
- }
-
- /* read len */
- blksize = 0;
- while (y--) {
- blksize = (blksize << 8) | (unsigned long)in[x++];
- }
- }
-
- /* would this blksize overflow? */
- if (x + blksize > inlen) {
- return CRYPT_INVALID_PACKET;
- }
-
- /* mark all as unused */
- for (i = 0; i < (int)outlen; i++) {
- list[i].used = 0;
- }
-
- /* ok read data */
- inlen = blksize;
- for (i = 0; i < (int)outlen; i++) {
- z = 0;
- type = list[i].type;
- size = list[i].size;
- data = list[i].data;
- if (!ordered && list[i].used == 1) { continue; }
-
- if (type == LTC_ASN1_EOL) {
- break;
- }
-
- switch (type) {
- case LTC_ASN1_BOOLEAN:
- z = inlen;
- if ((err = der_decode_boolean(in + x, z, ((int *)data))) != CRYPT_OK) {
- if (!ordered) { continue; }
- goto LBL_ERR;
- }
- if ((err = der_length_boolean(&z)) != CRYPT_OK) {
- goto LBL_ERR;
- }
- break;
-
- case LTC_ASN1_INTEGER:
- z = inlen;
- if ((err = der_decode_integer(in + x, z, data)) != CRYPT_OK) {
- if (!ordered) { continue; }
- goto LBL_ERR;
- }
- if ((err = der_length_integer(data, &z)) != CRYPT_OK) {
- goto LBL_ERR;
- }
- break;
-
- case LTC_ASN1_SHORT_INTEGER:
- z = inlen;
- if ((err = der_decode_short_integer(in + x, z, data)) != CRYPT_OK) {
- if (!ordered) { continue; }
- goto LBL_ERR;
- }
- if ((err = der_length_short_integer(((unsigned long*)data)[0], &z)) != CRYPT_OK) {
- goto LBL_ERR;
- }
-
- break;
-
- case LTC_ASN1_BIT_STRING:
- z = inlen;
- if ((err = der_decode_bit_string(in + x, z, data, &size)) != CRYPT_OK) {
- if (!ordered) { continue; }
- goto LBL_ERR;
- }
- list[i].size = size;
- if ((err = der_length_bit_string(size, &z)) != CRYPT_OK) {
- goto LBL_ERR;
- }
- break;
-
- case LTC_ASN1_RAW_BIT_STRING:
- z = inlen;
- if ((err = der_decode_raw_bit_string(in + x, z, data, &size)) != CRYPT_OK) {
- if (!ordered) { continue; }
- goto LBL_ERR;
- }
- list[i].size = size;
- if ((err = der_length_bit_string(size, &z)) != CRYPT_OK) {
- goto LBL_ERR;
- }
- break;
-
- case LTC_ASN1_OCTET_STRING:
- z = inlen;
- if ((err = der_decode_octet_string(in + x, z, data, &size)) != CRYPT_OK) {
- if (!ordered) { continue; }
- goto LBL_ERR;
- }
- list[i].size = size;
- if ((err = der_length_octet_string(size, &z)) != CRYPT_OK) {
- goto LBL_ERR;
- }
- break;
-
- case LTC_ASN1_NULL:
- if (inlen < 2 || in[x] != 0x05 || in[x+1] != 0x00) {
- if (!ordered) { continue; }
- err = CRYPT_INVALID_PACKET;
- goto LBL_ERR;
- }
- z = 2;
- break;
-
- case LTC_ASN1_OBJECT_IDENTIFIER:
- z = inlen;
- if ((err = der_decode_object_identifier(in + x, z, data, &size)) != CRYPT_OK) {
- if (!ordered) { continue; }
- goto LBL_ERR;
- }
- list[i].size = size;
- if ((err = der_length_object_identifier(data, size, &z)) != CRYPT_OK) {
- goto LBL_ERR;
- }
- break;
-
- case LTC_ASN1_TELETEX_STRING:
- z = inlen;
- if ((err = der_decode_teletex_string(in + x, z, data, &size)) != CRYPT_OK) {
- if (!ordered) { continue; }
- goto LBL_ERR;
- }
- list[i].size = size;
- if ((err = der_length_teletex_string(data, size, &z)) != CRYPT_OK) {
- goto LBL_ERR;
- }
- break;
-
- case LTC_ASN1_IA5_STRING:
- z = inlen;
- if ((err = der_decode_ia5_string(in + x, z, data, &size)) != CRYPT_OK) {
- if (!ordered) { continue; }
- goto LBL_ERR;
- }
- list[i].size = size;
- if ((err = der_length_ia5_string(data, size, &z)) != CRYPT_OK) {
- goto LBL_ERR;
- }
- break;
-
-
- case LTC_ASN1_PRINTABLE_STRING:
- z = inlen;
- if ((err = der_decode_printable_string(in + x, z, data, &size)) != CRYPT_OK) {
- if (!ordered) { continue; }
- goto LBL_ERR;
- }
- list[i].size = size;
- if ((err = der_length_printable_string(data, size, &z)) != CRYPT_OK) {
- goto LBL_ERR;
- }
- break;
-
- case LTC_ASN1_UTF8_STRING:
- z = inlen;
- if ((err = der_decode_utf8_string(in + x, z, data, &size)) != CRYPT_OK) {
- if (!ordered) { continue; }
- goto LBL_ERR;
- }
- list[i].size = size;
- if ((err = der_length_utf8_string(data, size, &z)) != CRYPT_OK) {
- goto LBL_ERR;
- }
- break;
-
- case LTC_ASN1_UTCTIME:
- z = inlen;
- if ((err = der_decode_utctime(in + x, &z, data)) != CRYPT_OK) {
- if (!ordered) { continue; }
- goto LBL_ERR;
- }
- break;
-
- case LTC_ASN1_GENERALIZEDTIME:
- z = inlen;
- if ((err = der_decode_generalizedtime(in + x, &z, data)) != CRYPT_OK) {
- if (!ordered) { continue; }
- goto LBL_ERR;
- }
- break;
-
- case LTC_ASN1_SET:
- z = inlen;
- if ((err = der_decode_set(in + x, z, data, size)) != CRYPT_OK) {
- if (!ordered) { continue; }
- goto LBL_ERR;
- }
- if ((err = der_length_sequence(data, size, &z)) != CRYPT_OK) {
- goto LBL_ERR;
- }
- break;
-
- case LTC_ASN1_SETOF:
- case LTC_ASN1_SEQUENCE:
- /* detect if we have the right type */
- if ((type == LTC_ASN1_SETOF && (in[x] & 0x3F) != 0x31) || (type == LTC_ASN1_SEQUENCE && (in[x] & 0x3F) != 0x30)) {
- err = CRYPT_INVALID_PACKET;
- goto LBL_ERR;
- }
-
- z = inlen;
- if ((err = der_decode_sequence(in + x, z, data, size)) != CRYPT_OK) {
- if (!ordered) { continue; }
- goto LBL_ERR;
- }
- if ((err = der_length_sequence(data, size, &z)) != CRYPT_OK) {
- goto LBL_ERR;
- }
- break;
-
-
- case LTC_ASN1_CHOICE:
- z = inlen;
- if ((err = der_decode_choice(in + x, &z, data, size)) != CRYPT_OK) {
- if (!ordered) { continue; }
- goto LBL_ERR;
- }
- break;
-
- case LTC_ASN1_CONSTRUCTED:
- case LTC_ASN1_CONTEXT_SPECIFIC:
- case LTC_ASN1_EOL:
- err = CRYPT_INVALID_ARG;
- goto LBL_ERR;
- }
- x += z;
- inlen -= z;
- list[i].used = 1;
- if (!ordered) {
- /* restart the decoder */
- i = -1;
- }
- }
-
- for (i = 0; i < (int)outlen; i++) {
- if (list[i].used == 0) {
- err = CRYPT_INVALID_PACKET;
- goto LBL_ERR;
- }
- }
-
- if (inlen == 0) {
- err = CRYPT_OK;
- } else {
- err = CRYPT_INPUT_TOO_LONG;
- }
-
-LBL_ERR:
- return err;
+ return der_decode_custom_type_ex(in, inlen, NULL, list, outlen, flags);
}
#endif
diff --git a/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c b/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c
index 142ef95ad..2a2529d1b 100644
--- a/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c
+++ b/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c
@@ -15,42 +15,6 @@
#ifdef LTC_DER
-static unsigned long _fetch_length(const unsigned char *in, unsigned long inlen, unsigned long *data_offset)
-{
- unsigned long x, z;
-
- *data_offset = 0;
-
- /* skip type and read len */
- if (inlen < 2) {
- return 0xFFFFFFFF;
- }
- ++in; ++(*data_offset);
-
- /* read len */
- x = *in++; ++(*data_offset);
-
- /* <128 means literal */
- if (x < 128) {
- return x+*data_offset;
- }
- x &= 0x7F; /* the lower 7 bits are the length of the length */
- inlen -= 2;
-
- /* len means len of len! */
- if (x == 0 || x > 4 || x > inlen) {
- return 0xFFFFFFFF;
- }
-
- *data_offset += x;
- z = 0;
- while (x--) {
- z = (z<<8) | ((unsigned long)*in);
- ++in;
- }
- return z+*data_offset;
-}
-
static int _new_element(ltc_asn1_list **l)
{
/* alloc new link */
@@ -80,7 +44,7 @@ static int _new_element(ltc_asn1_list **l)
int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc_asn1_list **out)
{
ltc_asn1_list *l;
- unsigned long err, type, len, totlen, data_offset;
+ unsigned long err, identifier, len, totlen, data_offset, id_len, len_len;
void *realloc_tmp;
LTC_ARGCHK(in != NULL);
@@ -99,38 +63,76 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc
/* scan the input and and get lengths and what not */
while (*inlen) {
- /* read the type byte */
- type = *in;
-
- /* fetch length */
- len = _fetch_length(in, *inlen, &data_offset);
- if (len > *inlen) {
- err = CRYPT_INVALID_PACKET;
- goto error;
- }
-
/* alloc new link */
if ((err = _new_element(&l)) != CRYPT_OK) {
goto error;
}
- if ((type & 0x20) && (type != 0x30) && (type != 0x31)) {
- /* constructed, use the 'used' field to store the original identifier */
- l->used = type;
- /* treat constructed elements like SETs */
- type = 0x20;
+ id_len = *inlen;
+ if ((err = der_decode_asn1_identifier(in, &id_len, l)) != CRYPT_OK) {
+ goto error;
}
- else if ((type & 0xC0) == 0x80) {
- /* context-specific, use the 'used' field to store the original identifier */
- l->used = type;
- /* context-specific elements are treated as opaque data */
- type = 0x80;
+ /* read the type byte */
+ identifier = *in;
+
+ if (l->type != LTC_ASN1_EOL) {
+ /* fetch length */
+ len_len = *inlen - id_len;
+#if defined(LTC_TEST_DBG)
+ data_offset = 666;
+ len = 0;
+#endif
+ if ((err = der_decode_asn1_length(&in[id_len], &len_len, &len)) != CRYPT_OK) {
+#if defined(LTC_TEST_DBG)
+ fprintf(stderr, "E1 %02lx: hl=%4lu l=%4lu - %s (%s)\n", identifier, data_offset, len, der_asn1_tag_to_string_map[l->tag], error_to_string(err));
+#endif
+ goto error;
+ } else if (len > (*inlen - id_len - len_len)) {
+ err = CRYPT_INVALID_PACKET;
+#if defined(LTC_TEST_DBG)
+ fprintf(stderr, "E2 %02lx: hl=%4lu l=%4lu - %s (%s)\n", identifier, data_offset, len, der_asn1_tag_to_string_map[l->tag], error_to_string(err));
+#endif
+ goto error;
+ }
+ data_offset = id_len + len_len;
+#if defined(LTC_TEST_DBG) && LTC_TEST_DBG > 1
+ if (l->type == LTC_ASN1_CUSTOM_TYPE && l->class == LTC_ASN1_CL_CONTEXT_SPECIFIC) {
+ fprintf(stderr, "OK %02lx: hl=%4lu l=%4lu - Context Specific[%s %llu]\n", identifier, data_offset, len, der_asn1_pc_to_string_map[l->pc], l->tag);
+ } else {
+ fprintf(stderr, "OK %02lx: hl=%4lu l=%4lu - %s\n", identifier, data_offset, len, der_asn1_tag_to_string_map[l->tag]);
+ }
+#endif
+ len += data_offset;
+
+ if (l->type == LTC_ASN1_CUSTOM_TYPE) {
+ /* Custom type, use the 'used' field to store the original identifier */
+ l->used = identifier;
+ if (l->pc == LTC_ASN1_PC_CONSTRUCTED) {
+ /* treat constructed elements like SEQUENCEs */
+ identifier = 0x20;
+ } else {
+ /* primitive elements are treated as opaque data */
+ identifier = 0x80;
+ }
+ }
+ } else {
+ /* Init this so gcc won't complain,
+ * as this case will only be hit when we
+ * can't decode the identifier so the
+ * switch-case should go to default anyway...
+ */
+ data_offset = 0;
}
/* now switch on type */
- switch (type) {
+ switch (identifier) {
case 0x01: /* BOOLEAN */
- l->type = LTC_ASN1_BOOLEAN;
+ if (l->type != LTC_ASN1_BOOLEAN) {
+ err = CRYPT_PK_ASN1_ERROR;
+ goto error;
+ }
+
+ /* init field */
l->size = 1;
l->data = XCALLOC(1, sizeof(int));
@@ -144,8 +146,12 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc
break;
case 0x02: /* INTEGER */
+ if (l->type != LTC_ASN1_INTEGER) {
+ err = CRYPT_PK_ASN1_ERROR;
+ goto error;
+ }
+
/* init field */
- l->type = LTC_ASN1_INTEGER;
l->size = 1;
if ((err = mp_init(&l->data)) != CRYPT_OK) {
goto error;
@@ -163,8 +169,12 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc
break;
case 0x03: /* BIT */
+ if (l->type != LTC_ASN1_BIT_STRING) {
+ err = CRYPT_PK_ASN1_ERROR;
+ goto error;
+ }
+
/* init field */
- l->type = LTC_ASN1_BIT_STRING;
l->size = len * 8; /* *8 because we store decoded bits one per char and they are encoded 8 per char. */
if ((l->data = XCALLOC(1, l->size)) == NULL) {
@@ -182,9 +192,12 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc
break;
case 0x04: /* OCTET */
+ if (l->type != LTC_ASN1_OCTET_STRING) {
+ err = CRYPT_PK_ASN1_ERROR;
+ goto error;
+ }
/* init field */
- l->type = LTC_ASN1_OCTET_STRING;
l->size = len;
if ((l->data = XCALLOC(1, l->size)) == NULL) {
@@ -202,6 +215,10 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc
break;
case 0x05: /* NULL */
+ if (l->type != LTC_ASN1_NULL) {
+ err = CRYPT_PK_ASN1_ERROR;
+ goto error;
+ }
/* valid NULL is 0x05 0x00 */
if (in[0] != 0x05 || in[1] != 0x00) {
@@ -210,7 +227,6 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc
}
/* simple to store ;-) */
- l->type = LTC_ASN1_NULL;
l->data = NULL;
l->size = 0;
len = 2;
@@ -218,9 +234,12 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc
break;
case 0x06: /* OID */
+ if (l->type != LTC_ASN1_OBJECT_IDENTIFIER) {
+ err = CRYPT_PK_ASN1_ERROR;
+ goto error;
+ }
/* init field */
- l->type = LTC_ASN1_OBJECT_IDENTIFIER;
l->size = len;
if ((l->data = XCALLOC(len, sizeof(unsigned long))) == NULL) {
@@ -247,7 +266,10 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc
case 0x0C: /* UTF8 */
/* init field */
- l->type = LTC_ASN1_UTF8_STRING;
+ if (l->type != LTC_ASN1_UTF8_STRING) {
+ err = CRYPT_PK_ASN1_ERROR;
+ goto error;
+ }
l->size = len;
if ((l->data = XCALLOC(sizeof(wchar_t), l->size)) == NULL) {
@@ -265,9 +287,12 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc
break;
case 0x13: /* PRINTABLE */
+ if (l->type != LTC_ASN1_PRINTABLE_STRING) {
+ err = CRYPT_PK_ASN1_ERROR;
+ goto error;
+ }
/* init field */
- l->type = LTC_ASN1_PRINTABLE_STRING;
l->size = len;
if ((l->data = XCALLOC(1, l->size)) == NULL) {
@@ -285,9 +310,12 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc
break;
case 0x14: /* TELETEXT */
+ if (l->type != LTC_ASN1_TELETEX_STRING) {
+ err = CRYPT_PK_ASN1_ERROR;
+ goto error;
+ }
/* init field */
- l->type = LTC_ASN1_TELETEX_STRING;
l->size = len;
if ((l->data = XCALLOC(1, l->size)) == NULL) {
@@ -305,9 +333,12 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc
break;
case 0x16: /* IA5 */
+ if (l->type != LTC_ASN1_IA5_STRING) {
+ err = CRYPT_PK_ASN1_ERROR;
+ goto error;
+ }
/* init field */
- l->type = LTC_ASN1_IA5_STRING;
l->size = len;
if ((l->data = XCALLOC(1, l->size)) == NULL) {
@@ -325,9 +356,12 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc
break;
case 0x17: /* UTC TIME */
+ if (l->type != LTC_ASN1_UTCTIME) {
+ err = CRYPT_PK_ASN1_ERROR;
+ goto error;
+ }
/* init field */
- l->type = LTC_ASN1_UTCTIME;
l->size = 1;
if ((l->data = XCALLOC(1, sizeof(ltc_utctime))) == NULL) {
@@ -346,7 +380,12 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc
break;
case 0x18:
- l->type = LTC_ASN1_GENERALIZEDTIME;
+ if (l->type != LTC_ASN1_GENERALIZEDTIME) {
+ err = CRYPT_PK_ASN1_ERROR;
+ goto error;
+ }
+
+ /* init field */
l->size = len;
if ((l->data = XCALLOC(1, sizeof(ltc_generalizedtime))) == NULL) {
@@ -369,14 +408,23 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc
case 0x31: /* SET */
/* init field */
- if (type == 0x20) {
- l->type = LTC_ASN1_CONSTRUCTED;
+ if (identifier == 0x20) {
+ if (l->type != LTC_ASN1_CUSTOM_TYPE) {
+ err = CRYPT_PK_ASN1_ERROR;
+ goto error;
+ }
}
- else if (type == 0x30) {
- l->type = LTC_ASN1_SEQUENCE;
+ else if (identifier == 0x30) {
+ if (l->type != LTC_ASN1_SEQUENCE) {
+ err = CRYPT_PK_ASN1_ERROR;
+ goto error;
+ }
}
else {
- l->type = LTC_ASN1_SET;
+ if (l->type != LTC_ASN1_SET) {
+ err = CRYPT_PK_ASN1_ERROR;
+ goto error;
+ }
}
if ((l->data = XMALLOC(len)) == NULL) {
@@ -391,12 +439,19 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc
/* jump to the start of the data */
in += data_offset;
*inlen -= data_offset;
- len = len - data_offset;
+ len -= data_offset;
+
+ /* save the decoded ASN.1 len */
+ len_len = len;
/* Sequence elements go as child */
if ((err = der_decode_sequence_flexi(in, &len, &(l->child))) != CRYPT_OK) {
goto error;
}
+ if (len_len != len) {
+ err = CRYPT_PK_ASN1_ERROR;
+ goto error;
+ }
/* len update */
totlen += data_offset;
@@ -410,7 +465,10 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc
break;
case 0x80: /* Context-specific */
- l->type = LTC_ASN1_CONTEXT_SPECIFIC;
+ if (l->type != LTC_ASN1_CUSTOM_TYPE) {
+ err = CRYPT_PK_ASN1_ERROR;
+ goto error;
+ }
if ((l->data = XCALLOC(1, len - data_offset)) == NULL) {
err = CRYPT_MEM;
diff --git a/src/pk/asn1/der/sequence/der_decode_sequence_multi.c b/src/pk/asn1/der/sequence/der_decode_sequence_multi.c
index 1361b761b..280d7cdb5 100644
--- a/src/pk/asn1/der/sequence/der_decode_sequence_multi.c
+++ b/src/pk/asn1/der/sequence/der_decode_sequence_multi.c
@@ -21,27 +21,27 @@
Decode a SEQUENCE type using a VA list
@param in Input buffer
@param inlen Length of input in octets
- @remark <...> is of the form (int, unsigned long, void*)
+ @param a1 Initialized argument list #1
+ @param a2 Initialized argument list #2 (copy of #1)
+ @param flags c.f. enum ltc_der_seq
@return CRYPT_OK on success
*/
-int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
+static int _der_decode_sequence_va(const unsigned char *in, unsigned long inlen, va_list a1, va_list a2, unsigned int flags)
{
int err;
ltc_asn1_type type;
unsigned long size, x;
void *data;
- va_list args;
ltc_asn1_list *list;
LTC_ARGCHK(in != NULL);
/* get size of output that will be required */
- va_start(args, inlen);
x = 0;
for (;;) {
- type = (ltc_asn1_type)va_arg(args, int);
- size = va_arg(args, unsigned long);
- data = va_arg(args, void*);
+ type = (ltc_asn1_type)va_arg(a1, int);
+ size = va_arg(a1, unsigned long);
+ data = va_arg(a1, void*);
LTC_UNUSED_PARAM(size);
LTC_UNUSED_PARAM(data);
@@ -72,13 +72,10 @@ int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
break;
case LTC_ASN1_EOL:
- case LTC_ASN1_CONSTRUCTED:
- case LTC_ASN1_CONTEXT_SPECIFIC:
- va_end(args);
+ case LTC_ASN1_CUSTOM_TYPE:
return CRYPT_INVALID_ARG;
}
}
- va_end(args);
/* allocate structure for x elements */
if (x == 0) {
@@ -91,12 +88,11 @@ int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
}
/* fill in the structure */
- va_start(args, inlen);
x = 0;
for (;;) {
- type = (ltc_asn1_type)va_arg(args, int);
- size = va_arg(args, unsigned long);
- data = va_arg(args, void*);
+ type = (ltc_asn1_type)va_arg(a2, int);
+ size = va_arg(a2, unsigned long);
+ data = va_arg(a2, void*);
if (type == LTC_ASN1_EOL) {
break;
@@ -125,18 +121,67 @@ int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
break;
/* coverity[dead_error_line] */
case LTC_ASN1_EOL:
- case LTC_ASN1_CONSTRUCTED:
- case LTC_ASN1_CONTEXT_SPECIFIC:
+ case LTC_ASN1_CUSTOM_TYPE:
break;
}
}
- va_end(args);
- err = der_decode_sequence(in, inlen, list, x);
+ err = der_decode_sequence_ex(in, inlen, list, x, flags);
XFREE(list);
return err;
}
+/**
+ Decode a SEQUENCE type using a VA list
+ @param in Input buffer
+ @param inlen Length of input in octets
+ @remark <...> is of the form (int, unsigned long, void*)
+ @return CRYPT_OK on success
+*/
+int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
+{
+ va_list a1, a2;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+
+ va_start(a1, inlen);
+ va_start(a2, inlen);
+
+ err = _der_decode_sequence_va(in, inlen, a1, a2, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_RELAXED);
+
+ va_end(a2);
+ va_end(a1);
+
+ return err;
+}
+
+/**
+ Decode a SEQUENCE type using a VA list
+ @param in Input buffer
+ @param inlen Length of input in octets
+ @param flags c.f. enum ltc_der_seq
+ @remark <...> is of the form (int, unsigned long, void*)
+ @return CRYPT_OK on success
+*/
+int der_decode_sequence_multi_ex(const unsigned char *in, unsigned long inlen, unsigned int flags, ...)
+{
+ va_list a1, a2;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+
+ va_start(a1, flags);
+ va_start(a2, flags);
+
+ err = _der_decode_sequence_va(in, inlen, a1, a2, flags);
+
+ va_end(a2);
+ va_end(a1);
+
+ return err;
+}
+
#endif
diff --git a/src/pk/asn1/der/sequence/der_encode_sequence_ex.c b/src/pk/asn1/der/sequence/der_encode_sequence_ex.c
index 2b42ff482..1a5d96817 100644
--- a/src/pk/asn1/der/sequence/der_encode_sequence_ex.c
+++ b/src/pk/asn1/der/sequence/der_encode_sequence_ex.c
@@ -52,21 +52,11 @@ int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen,
x = 0;
out[x++] = (type_of == LTC_ASN1_SEQUENCE) ? 0x30 : 0x31;
- if (z < 128) {
- out[x++] = (unsigned char)z;
- } else if (z < 256) {
- out[x++] = 0x81;
- out[x++] = (unsigned char)z;
- } else if (z < 65536UL) {
- out[x++] = 0x82;
- out[x++] = (unsigned char)((z>>8UL)&255);
- out[x++] = (unsigned char)(z&255);
- } else if (z < 16777216UL) {
- out[x++] = 0x83;
- out[x++] = (unsigned char)((z>>16UL)&255);
- out[x++] = (unsigned char)((z>>8UL)&255);
- out[x++] = (unsigned char)(z&255);
+ y = *outlen - x;
+ if ((err = der_encode_asn1_length(z, &out[x], &y)) != CRYPT_OK) {
+ goto LBL_ERR;
}
+ x += y;
/* store data */
*outlen -= x;
@@ -191,9 +181,14 @@ int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen,
}
break;
+ case LTC_ASN1_CUSTOM_TYPE:
+ z = *outlen;
+ if ((err = der_encode_custom_type(&list[i], out + x, &z)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ break;
+
case LTC_ASN1_CHOICE:
- case LTC_ASN1_CONSTRUCTED:
- case LTC_ASN1_CONTEXT_SPECIFIC:
case LTC_ASN1_EOL:
case LTC_ASN1_TELETEX_STRING:
err = CRYPT_INVALID_ARG;
diff --git a/src/pk/asn1/der/sequence/der_encode_sequence_multi.c b/src/pk/asn1/der/sequence/der_encode_sequence_multi.c
index c1b40c775..c8ec59a95 100644
--- a/src/pk/asn1/der/sequence/der_encode_sequence_multi.c
+++ b/src/pk/asn1/der/sequence/der_encode_sequence_multi.c
@@ -71,8 +71,7 @@ int der_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...)
break;
case LTC_ASN1_CHOICE:
- case LTC_ASN1_CONSTRUCTED:
- case LTC_ASN1_CONTEXT_SPECIFIC:
+ case LTC_ASN1_CUSTOM_TYPE:
case LTC_ASN1_EOL:
case LTC_ASN1_TELETEX_STRING:
va_end(args);
@@ -124,8 +123,7 @@ int der_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...)
break;
case LTC_ASN1_CHOICE:
- case LTC_ASN1_CONSTRUCTED:
- case LTC_ASN1_CONTEXT_SPECIFIC:
+ case LTC_ASN1_CUSTOM_TYPE:
case LTC_ASN1_EOL:
case LTC_ASN1_TELETEX_STRING:
va_end(args);
diff --git a/src/pk/asn1/der/sequence/der_length_sequence.c b/src/pk/asn1/der/sequence/der_length_sequence.c
index aed7cc2a3..a80f96b02 100644
--- a/src/pk/asn1/der/sequence/der_length_sequence.c
+++ b/src/pk/asn1/der/sequence/der_length_sequence.c
@@ -33,7 +33,7 @@ int der_length_sequence_ex(ltc_asn1_list *list, unsigned long inlen,
{
int err;
ltc_asn1_type type;
- unsigned long size, x, y, i, z;
+ unsigned long size, x, y, i;
void *data;
LTC_ARGCHK(list != NULL);
@@ -50,6 +50,9 @@ int der_length_sequence_ex(ltc_asn1_list *list, unsigned long inlen,
break;
}
+ /* some items may be optional during import */
+ if (!list[i].used && list[i].optional) continue;
+
switch (type) {
case LTC_ASN1_BOOLEAN:
if ((err = der_length_boolean(&x)) != CRYPT_OK) {
@@ -140,6 +143,13 @@ int der_length_sequence_ex(ltc_asn1_list *list, unsigned long inlen,
y += x;
break;
+ case LTC_ASN1_CUSTOM_TYPE:
+ if ((err = der_length_custom_type(&list[i], &x, NULL)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ y += x;
+ break;
+
case LTC_ASN1_SET:
case LTC_ASN1_SETOF:
case LTC_ASN1_SEQUENCE:
@@ -149,37 +159,23 @@ int der_length_sequence_ex(ltc_asn1_list *list, unsigned long inlen,
y += x;
break;
-
case LTC_ASN1_CHOICE:
- case LTC_ASN1_CONSTRUCTED:
- case LTC_ASN1_CONTEXT_SPECIFIC:
case LTC_ASN1_EOL:
err = CRYPT_INVALID_ARG;
goto LBL_ERR;
}
}
- /* calc header size */
- z = y;
- if (y < 128) {
- y += 2;
- } else if (y < 256) {
- /* 0x30 0x81 LL */
- y += 3;
- } else if (y < 65536UL) {
- /* 0x30 0x82 LL LL */
- y += 4;
- } else if (y < 16777216UL) {
- /* 0x30 0x83 LL LL LL */
- y += 5;
- } else {
- err = CRYPT_INVALID_ARG;
+ if ((err = der_length_asn1_length(y, &x)) != CRYPT_OK) {
goto LBL_ERR;
}
+ if (payloadlen != NULL) {
+ *payloadlen = y;
+ }
+
/* store size */
- if (payloadlen) *payloadlen = z;
- *outlen = y;
+ *outlen = y + x + 1;
err = CRYPT_OK;
LBL_ERR:
diff --git a/src/pk/asn1/der/sequence/der_sequence_shrink.c b/src/pk/asn1/der/sequence/der_sequence_shrink.c
index 9b9e036aa..fdfe91bbb 100644
--- a/src/pk/asn1/der/sequence/der_sequence_shrink.c
+++ b/src/pk/asn1/der/sequence/der_sequence_shrink.c
@@ -32,7 +32,7 @@ void der_sequence_shrink(ltc_asn1_list *in)
}
switch (in->type) {
- case LTC_ASN1_CONSTRUCTED:
+ case LTC_ASN1_CUSTOM_TYPE:
case LTC_ASN1_SET:
case LTC_ASN1_SEQUENCE : if (in->data != NULL) { XFREE(in->data); in->data = NULL; } break;
default: break;
diff --git a/src/pk/asn1/der/set/der_encode_set.c b/src/pk/asn1/der/set/der_encode_set.c
index fef3092b7..a3485f2d9 100644
--- a/src/pk/asn1/der/set/der_encode_set.c
+++ b/src/pk/asn1/der/set/der_encode_set.c
@@ -18,30 +18,7 @@
/* LTC define to ASN.1 TAG */
static int _ltc_to_asn1(ltc_asn1_type v)
{
- switch (v) {
- case LTC_ASN1_BOOLEAN: return 0x01;
- case LTC_ASN1_INTEGER:
- case LTC_ASN1_SHORT_INTEGER: return 0x02;
- case LTC_ASN1_RAW_BIT_STRING:
- case LTC_ASN1_BIT_STRING: return 0x03;
- case LTC_ASN1_OCTET_STRING: return 0x04;
- case LTC_ASN1_NULL: return 0x05;
- case LTC_ASN1_OBJECT_IDENTIFIER: return 0x06;
- case LTC_ASN1_UTF8_STRING: return 0x0C;
- case LTC_ASN1_PRINTABLE_STRING: return 0x13;
- case LTC_ASN1_TELETEX_STRING: return 0x14;
- case LTC_ASN1_IA5_STRING: return 0x16;
- case LTC_ASN1_UTCTIME: return 0x17;
- case LTC_ASN1_GENERALIZEDTIME: return 0x18;
- case LTC_ASN1_SEQUENCE: return 0x30;
- case LTC_ASN1_SET:
- case LTC_ASN1_SETOF: return 0x31;
- case LTC_ASN1_CHOICE:
- case LTC_ASN1_CONSTRUCTED:
- case LTC_ASN1_CONTEXT_SPECIFIC:
- case LTC_ASN1_EOL: return -1;
- }
- return -1;
+ return der_asn1_type_to_identifier_map[v];
}
diff --git a/src/pk/asn1/der/short_integer/der_length_short_integer.c b/src/pk/asn1/der/short_integer/der_length_short_integer.c
index 52d0e1aef..8c1de2896 100644
--- a/src/pk/asn1/der/short_integer/der_length_short_integer.c
+++ b/src/pk/asn1/der/short_integer/der_length_short_integer.c
@@ -23,7 +23,8 @@
*/
int der_length_short_integer(unsigned long num, unsigned long *outlen)
{
- unsigned long z, y, len;
+ unsigned long z, y;
+ int err;
LTC_ARGCHK(outlen != NULL);
@@ -41,22 +42,15 @@ int der_length_short_integer(unsigned long num, unsigned long *outlen)
/* handle zero */
if (z == 0) {
z = 1;
+ } else if ((num&(1UL<<((z<<3) - 1))) != 0) {
+ /* in case msb is set */
+ ++z;
}
- /* we need a 0x02 to indicate it's INTEGER */
- len = 1;
-
- /* length byte */
- ++len;
-
- /* bytes in value */
- len += z;
-
- /* see if msb is set */
- len += (num&(1UL<<((z<<3) - 1))) ? 1 : 0;
-
- /* return length */
- *outlen = len;
+ if ((err = der_length_asn1_length(z, &y)) != CRYPT_OK) {
+ return err;
+ }
+ *outlen = 1 + y + z;
return CRYPT_OK;
}
diff --git a/src/pk/asn1/der/teletex_string/der_decode_teletex_string.c b/src/pk/asn1/der/teletex_string/der_decode_teletex_string.c
index 0c7c3c8f2..cd530a2be 100644
--- a/src/pk/asn1/der/teletex_string/der_decode_teletex_string.c
+++ b/src/pk/asn1/der/teletex_string/der_decode_teletex_string.c
@@ -27,7 +27,7 @@ int der_decode_teletex_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
unsigned long x, y, len;
- int t;
+ int t, err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
@@ -44,23 +44,12 @@ int der_decode_teletex_string(const unsigned char *in, unsigned long inlen,
}
x = 1;
- /* decode the length */
- if (in[x] & 0x80) {
- /* valid # of bytes in length are 1,2,3 */
- y = in[x] & 0x7F;
- if ((y == 0) || (y > 3) || ((x + y) > inlen)) {
- return CRYPT_INVALID_PACKET;
- }
-
- /* read the length in */
- len = 0;
- ++x;
- while (y--) {
- len = (len << 8) | in[x++];
- }
- } else {
- len = in[x++] & 0x7F;
+ /* get the length of the data */
+ y = inlen - x;
+ if ((err = der_decode_asn1_length(in + x, &y, &len)) != CRYPT_OK) {
+ return err;
}
+ x += y;
/* is it too long? */
if (len > *outlen) {
@@ -68,7 +57,7 @@ int der_decode_teletex_string(const unsigned char *in, unsigned long inlen,
return CRYPT_BUFFER_OVERFLOW;
}
- if (len + x > inlen) {
+ if (len > (inlen - x)) {
return CRYPT_INVALID_PACKET;
}
diff --git a/src/pk/asn1/der/teletex_string/der_length_teletex_string.c b/src/pk/asn1/der/teletex_string/der_length_teletex_string.c
index 29fe5b0b8..a35c6d769 100644
--- a/src/pk/asn1/der/teletex_string/der_length_teletex_string.c
+++ b/src/pk/asn1/der/teletex_string/der_length_teletex_string.c
@@ -170,6 +170,7 @@ int der_teletex_value_decode(int v)
int der_length_teletex_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen)
{
unsigned long x;
+ int err;
LTC_ARGCHK(outlen != NULL);
LTC_ARGCHK(octets != NULL);
@@ -181,21 +182,10 @@ int der_length_teletex_string(const unsigned char *octets, unsigned long noctets
}
}
- if (noctets < 128) {
- /* 16 LL DD DD DD ... */
- *outlen = 2 + noctets;
- } else if (noctets < 256) {
- /* 16 81 LL DD DD DD ... */
- *outlen = 3 + noctets;
- } else if (noctets < 65536UL) {
- /* 16 82 LL LL DD DD DD ... */
- *outlen = 4 + noctets;
- } else if (noctets < 16777216UL) {
- /* 16 83 LL LL LL DD DD DD ... */
- *outlen = 5 + noctets;
- } else {
- return CRYPT_INVALID_ARG;
+ if ((err = der_length_asn1_length(noctets, &x)) != CRYPT_OK) {
+ return err;
}
+ *outlen = 1 + x + noctets;
return CRYPT_OK;
}
diff --git a/src/pk/asn1/der/utf8/der_decode_utf8_string.c b/src/pk/asn1/der/utf8/der_decode_utf8_string.c
index 195a3f50a..c86d66039 100644
--- a/src/pk/asn1/der/utf8/der_decode_utf8_string.c
+++ b/src/pk/asn1/der/utf8/der_decode_utf8_string.c
@@ -46,25 +46,14 @@ int der_decode_utf8_string(const unsigned char *in, unsigned long inlen,
}
x = 1;
- /* decode the length */
- if (in[x] & 0x80) {
- /* valid # of bytes in length are 1,2,3 */
- y = in[x] & 0x7F;
- if ((y == 0) || (y > 3) || ((x + y) > inlen)) {
- return CRYPT_INVALID_PACKET;
- }
-
- /* read the length in */
- len = 0;
- ++x;
- while (y--) {
- len = (len << 8) | in[x++];
- }
- } else {
- len = in[x++] & 0x7F;
+ /* get the length of the data */
+ y = inlen - x;
+ if ((err = der_decode_asn1_length(in + x, &y, &len)) != CRYPT_OK) {
+ return err;
}
+ x += y;
- if (len + x > inlen) {
+ if (len > (inlen - x)) {
return CRYPT_INVALID_PACKET;
}
diff --git a/src/pk/asn1/der/utf8/der_encode_utf8_string.c b/src/pk/asn1/der/utf8/der_encode_utf8_string.c
index 4c2030ff4..1c6e09b5e 100644
--- a/src/pk/asn1/der/utf8/der_encode_utf8_string.c
+++ b/src/pk/asn1/der/utf8/der_encode_utf8_string.c
@@ -28,6 +28,7 @@ int der_encode_utf8_string(const wchar_t *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
unsigned long x, y, len;
+ int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
@@ -38,46 +39,26 @@ int der_encode_utf8_string(const wchar_t *in, unsigned long inlen,
if (!der_utf8_valid_char(in[x])) return CRYPT_INVALID_ARG;
len += der_utf8_charsize(in[x]);
}
-
- if (len < 128) {
- y = 2 + len;
- } else if (len < 256) {
- y = 3 + len;
- } else if (len < 65536UL) {
- y = 4 + len;
- } else if (len < 16777216UL) {
- y = 5 + len;
- } else {
- return CRYPT_INVALID_ARG;
+ if ((err = der_length_asn1_length(len, &x)) != CRYPT_OK) {
+ return err;
}
+ x += len + 1;
/* too big? */
- if (y > *outlen) {
- *outlen = y;
+ if (x > *outlen) {
+ *outlen = x;
return CRYPT_BUFFER_OVERFLOW;
}
/* encode the header+len */
x = 0;
out[x++] = 0x0C;
- if (len < 128) {
- out[x++] = (unsigned char)len;
- } else if (len < 256) {
- out[x++] = 0x81;
- out[x++] = (unsigned char)len;
- } else if (len < 65536UL) {
- out[x++] = 0x82;
- out[x++] = (unsigned char)((len>>8)&255);
- out[x++] = (unsigned char)(len&255);
- } else if (len < 16777216UL) {
- out[x++] = 0x83;
- out[x++] = (unsigned char)((len>>16)&255);
- out[x++] = (unsigned char)((len>>8)&255);
- out[x++] = (unsigned char)(len&255);
- } else {
- /* coverity[dead_error_line] */
- return CRYPT_INVALID_ARG;
+
+ y = *outlen - x;
+ if ((err = der_encode_asn1_length(len, out + x, &y)) != CRYPT_OK) {
+ return err;
}
+ x += y;
/* store UTF8 */
for (y = 0; y < inlen; y++) {
@@ -91,7 +72,7 @@ int der_encode_utf8_string(const wchar_t *in, unsigned long inlen,
}
}
- /* retun length */
+ /* return length */
*outlen = x;
return CRYPT_OK;
diff --git a/src/pk/asn1/der/utf8/der_length_utf8_string.c b/src/pk/asn1/der/utf8/der_length_utf8_string.c
index 88f4355e3..b4292846d 100644
--- a/src/pk/asn1/der/utf8/der_length_utf8_string.c
+++ b/src/pk/asn1/der/utf8/der_length_utf8_string.c
@@ -65,6 +65,7 @@ int der_utf8_valid_char(const wchar_t c)
int der_length_utf8_string(const wchar_t *in, unsigned long noctets, unsigned long *outlen)
{
unsigned long x, len;
+ int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(outlen != NULL);
@@ -75,21 +76,10 @@ int der_length_utf8_string(const wchar_t *in, unsigned long noctets, unsigned lo
len += der_utf8_charsize(in[x]);
}
- if (len < 128) {
- /* 0C LL DD DD DD ... */
- *outlen = 2 + len;
- } else if (len < 256) {
- /* 0C 81 LL DD DD DD ... */
- *outlen = 3 + len;
- } else if (len < 65536UL) {
- /* 0C 82 LL LL DD DD DD ... */
- *outlen = 4 + len;
- } else if (len < 16777216UL) {
- /* 0C 83 LL LL LL DD DD DD ... */
- *outlen = 5 + len;
- } else {
- return CRYPT_INVALID_ARG;
+ if ((err = der_length_asn1_length(len, &x)) != CRYPT_OK) {
+ return err;
}
+ *outlen = 1 + x + len;
return CRYPT_OK;
}
diff --git a/src/pk/asn1/der/sequence/der_decode_subject_public_key_info.c b/src/pk/asn1/x509/x509_decode_subject_public_key_info.c
similarity index 85%
rename from src/pk/asn1/der/sequence/der_decode_subject_public_key_info.c
rename to src/pk/asn1/x509/x509_decode_subject_public_key_info.c
index 682618179..c68b4a3bc 100644
--- a/src/pk/asn1/der/sequence/der_decode_subject_public_key_info.c
+++ b/src/pk/asn1/x509/x509_decode_subject_public_key_info.c
@@ -7,9 +7,10 @@
* guarantee it works.
*/
#include "tomcrypt.h"
+
/**
- @file der_decode_subject_public_key_info.c
- ASN.1 DER, encode a Subject Public Key structure --nmav
+ @file x509_decode_subject_public_key_info.c
+ ASN.1 DER/X.509, encode a SubjectPublicKeyInfo structure --nmav
*/
#ifdef LTC_DER
@@ -25,7 +26,7 @@
* }
*/
/**
- Decode a subject public key info
+ Decode a SubjectPublicKeyInfo
@param in The input buffer
@param inlen The length of the input buffer
@param algorithm One out of the enum #public_key_algorithms
@@ -33,12 +34,12 @@
@param public_key_len [in/out] The length of the public key buffer and the written length
@param parameters_type The parameters' type out of the enum ltc_asn1_type
@param parameters The parameters to include
- @param parameters_len The number of parameters to include
+ @param parameters_len [in/out]The number of parameters to include
@return CRYPT_OK on success
*/
-int der_decode_subject_public_key_info(const unsigned char *in, unsigned long inlen,
+int x509_decode_subject_public_key_info(const unsigned char *in, unsigned long inlen,
unsigned int algorithm, void* public_key, unsigned long* public_key_len,
- unsigned long parameters_type, ltc_asn1_list* parameters, unsigned long parameters_len)
+ unsigned long parameters_type, void* parameters, unsigned long *parameters_len)
{
int err;
unsigned long len;
@@ -51,6 +52,7 @@ int der_decode_subject_public_key_info(const unsigned char *in, unsigned long in
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(inlen != 0);
LTC_ARGCHK(public_key_len != NULL);
+ LTC_ARGCHK(parameters_len != NULL);
err = pk_get_oid(algorithm, &oid);
if (err != CRYPT_OK) {
@@ -66,7 +68,7 @@ int der_decode_subject_public_key_info(const unsigned char *in, unsigned long in
/* this includes the internal hash ID and optional params (NULL in this case) */
LTC_SET_ASN1(alg_id, 0, LTC_ASN1_OBJECT_IDENTIFIER, tmpoid, sizeof(tmpoid)/sizeof(tmpoid[0]));
- LTC_SET_ASN1(alg_id, 1, (ltc_asn1_type)parameters_type, parameters, parameters_len);
+ LTC_SET_ASN1(alg_id, 1, (ltc_asn1_type)parameters_type, parameters, *parameters_len);
/* the actual format of the SSL DER key is odd, it stores a RSAPublicKey
* in a **BIT** string ... so we have to extract it then proceed to convert bit to octet
@@ -79,6 +81,8 @@ int der_decode_subject_public_key_info(const unsigned char *in, unsigned long in
goto LBL_ERR;
}
+ *parameters_len = alg_id[1].size;
+
if ((alg_id[0].size != oid.OIDlen) ||
XMEMCMP(oid.OID, alg_id[0].data, oid.OIDlen * sizeof(oid.OID[0]))) {
/* OID mismatch */
diff --git a/src/pk/asn1/der/sequence/der_encode_subject_public_key_info.c b/src/pk/asn1/x509/x509_encode_subject_public_key_info.c
similarity index 90%
rename from src/pk/asn1/der/sequence/der_encode_subject_public_key_info.c
rename to src/pk/asn1/x509/x509_encode_subject_public_key_info.c
index dcb869a9e..8148a185d 100644
--- a/src/pk/asn1/der/sequence/der_encode_subject_public_key_info.c
+++ b/src/pk/asn1/x509/x509_encode_subject_public_key_info.c
@@ -9,8 +9,8 @@
#include "tomcrypt.h"
/**
- @file der_encode_subject_public_key_info.c
- ASN.1 DER, encode a Subject Public Key structure --nmav
+ @file x509_encode_subject_public_key_info.c
+ ASN.1 DER/X.509, encode a SubjectPublicKeyInfo structure --nmav
*/
#ifdef LTC_DER
@@ -26,7 +26,7 @@
* }
*/
/**
- Encode a subject public key info
+ Encode a SubjectPublicKeyInfo
@param out The output buffer
@param outlen [in/out] Length of buffer and resulting length of output
@param algorithm One out of the enum #public_key_algorithms
@@ -37,7 +37,7 @@
@param parameters_len The number of parameters to include
@return CRYPT_OK on success
*/
-int der_encode_subject_public_key_info(unsigned char *out, unsigned long *outlen,
+int x509_encode_subject_public_key_info(unsigned char *out, unsigned long *outlen,
unsigned int algorithm, void* public_key, unsigned long public_key_len,
unsigned long parameters_type, void* parameters, unsigned long parameters_len)
{
diff --git a/src/pk/dsa/dsa_export.c b/src/pk/dsa/dsa_export.c
index 1f6bb5a3d..dde545836 100644
--- a/src/pk/dsa/dsa_export.c
+++ b/src/pk/dsa/dsa_export.c
@@ -86,7 +86,7 @@ int dsa_export(unsigned char *out, unsigned long *outlen, int type, dsa_key *key
LTC_SET_ASN1(int_list, 1, LTC_ASN1_INTEGER, key->q, 1UL);
LTC_SET_ASN1(int_list, 2, LTC_ASN1_INTEGER, key->g, 1UL);
- err = der_encode_subject_public_key_info(out, outlen, PKA_DSA, tmp,
+ err = x509_encode_subject_public_key_info(out, outlen, PKA_DSA, tmp,
tmplen, LTC_ASN1_SEQUENCE, int_list,
sizeof(int_list) / sizeof(int_list[0]));
diff --git a/src/pk/dsa/dsa_import.c b/src/pk/dsa/dsa_import.c
index e6a756027..5e77b1e73 100644
--- a/src/pk/dsa/dsa_import.c
+++ b/src/pk/dsa/dsa_import.c
@@ -25,7 +25,7 @@
int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key)
{
int err, stat;
- unsigned long zero = 0;
+ unsigned long zero = 0, len;
unsigned char* tmpbuf = NULL;
unsigned char flags[1];
@@ -102,9 +102,10 @@ int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key)
goto LBL_ERR;
}
- err = der_decode_subject_public_key_info(in, inlen, PKA_DSA,
+ len = 3;
+ err = x509_decode_subject_public_key_info(in, inlen, PKA_DSA,
tmpbuf, &tmpbuf_len,
- LTC_ASN1_SEQUENCE, params, 3);
+ LTC_ASN1_SEQUENCE, params, &len);
if (err != CRYPT_OK) {
XFREE(tmpbuf);
goto LBL_ERR;
diff --git a/src/pk/dsa/dsa_verify_hash.c b/src/pk/dsa/dsa_verify_hash.c
index 3d3fab5fd..eb642d5b1 100644
--- a/src/pk/dsa/dsa_verify_hash.c
+++ b/src/pk/dsa/dsa_verify_hash.c
@@ -111,7 +111,7 @@ int dsa_verify_hash(const unsigned char *sig, unsigned long siglen,
LTC_SET_ASN1(sig_seq, 0, LTC_ASN1_INTEGER, r, 1UL);
LTC_SET_ASN1(sig_seq, 1, LTC_ASN1_INTEGER, s, 1UL);
- err = der_decode_sequence(sig, siglen, sig_seq, 2);
+ err = der_decode_sequence_strict(sig, siglen, sig_seq, 2);
if (err != CRYPT_OK) {
goto LBL_ERR;
}
diff --git a/src/pk/ecc/ecc_verify_hash.c b/src/pk/ecc/ecc_verify_hash.c
index af1775878..f2b26c099 100644
--- a/src/pk/ecc/ecc_verify_hash.c
+++ b/src/pk/ecc/ecc_verify_hash.c
@@ -66,7 +66,7 @@ static int _ecc_verify_hash(const unsigned char *sig, unsigned long siglen,
}
else {
/* ASN.1 format */
- if ((err = der_decode_sequence_multi(sig, siglen,
+ if ((err = der_decode_sequence_multi_ex(sig, siglen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_STRICT,
LTC_ASN1_INTEGER, 1UL, r,
LTC_ASN1_INTEGER, 1UL, s,
LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { goto error; }
diff --git a/src/pk/rsa/rsa_export.c b/src/pk/rsa/rsa_export.c
index a9885de8f..b156a83ff 100644
--- a/src/pk/rsa/rsa_export.c
+++ b/src/pk/rsa/rsa_export.c
@@ -79,7 +79,7 @@ int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key
goto finish;
}
- err = der_encode_subject_public_key_info(out, outlen,
+ err = x509_encode_subject_public_key_info(out, outlen,
PKA_RSA, tmp, tmplen, LTC_ASN1_NULL, NULL, 0);
finish:
diff --git a/src/pk/rsa/rsa_import.c b/src/pk/rsa/rsa_import.c
index 84cd6f650..857717837 100644
--- a/src/pk/rsa/rsa_import.c
+++ b/src/pk/rsa/rsa_import.c
@@ -27,7 +27,7 @@ int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key)
int err;
void *zero;
unsigned char *tmpbuf=NULL;
- unsigned long tmpbuf_len;
+ unsigned long tmpbuf_len, len;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(key != NULL);
@@ -47,9 +47,10 @@ int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key)
goto LBL_ERR;
}
- err = der_decode_subject_public_key_info(in, inlen,
+ len = 0;
+ err = x509_decode_subject_public_key_info(in, inlen,
PKA_RSA, tmpbuf, &tmpbuf_len,
- LTC_ASN1_NULL, NULL, 0);
+ LTC_ASN1_NULL, NULL, &len);
if (err == CRYPT_OK) { /* SubjectPublicKeyInfo format */
diff --git a/src/pk/rsa/rsa_import_x509.c b/src/pk/rsa/rsa_import_x509.c
index 0f2d5f1ce..aa35e644e 100644
--- a/src/pk/rsa/rsa_import_x509.c
+++ b/src/pk/rsa/rsa_import_x509.c
@@ -26,7 +26,7 @@ int rsa_import_x509(const unsigned char *in, unsigned long inlen, rsa_key *key)
{
int err;
unsigned char *tmpbuf;
- unsigned long tmpbuf_len, tmp_inlen;
+ unsigned long tmpbuf_len, tmp_inlen, len;
ltc_asn1_list *decoded_list = NULL, *l;
LTC_ARGCHK(in != NULL);
@@ -77,9 +77,10 @@ int rsa_import_x509(const unsigned char *in, unsigned long inlen, rsa_key *key)
l->child->type == LTC_ASN1_SEQUENCE && l->child->child &&
l->child->child->type == LTC_ASN1_OBJECT_IDENTIFIER && l->child->next &&
l->child->next->type == LTC_ASN1_BIT_STRING) {
- err = der_decode_subject_public_key_info(l->data, l->size,
+ len = 0;
+ err = x509_decode_subject_public_key_info(l->data, l->size,
PKA_RSA, tmpbuf, &tmpbuf_len,
- LTC_ASN1_NULL, NULL, 0);
+ LTC_ASN1_NULL, NULL, &len);
if (err == CRYPT_OK) {
/* now it should be SEQUENCE { INTEGER, INTEGER } */
if ((err = der_decode_sequence_multi(tmpbuf, tmpbuf_len,
diff --git a/src/pk/rsa/rsa_verify_hash.c b/src/pk/rsa/rsa_verify_hash.c
index b5846965f..361f23788 100644
--- a/src/pk/rsa/rsa_verify_hash.c
+++ b/src/pk/rsa/rsa_verify_hash.c
@@ -142,10 +142,10 @@ int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen,
LTC_SET_ASN1(siginfo, 0, LTC_ASN1_SEQUENCE, digestinfo, 2);
LTC_SET_ASN1(siginfo, 1, LTC_ASN1_OCTET_STRING, tmpbuf, siglen);
- if ((err = der_decode_sequence(out, outlen, siginfo, 2)) != CRYPT_OK) {
+ if ((err = der_decode_sequence_strict(out, outlen, siginfo, 2)) != CRYPT_OK) {
/* fallback to Legacy:missing NULL */
LTC_SET_ASN1(siginfo, 0, LTC_ASN1_SEQUENCE, digestinfo, 1);
- if ((err = der_decode_sequence(out, outlen, siginfo, 2)) != CRYPT_OK) {
+ if ((err = der_decode_sequence_strict(out, outlen, siginfo, 2)) != CRYPT_OK) {
XFREE(out);
goto bail_2;
}
diff --git a/tests/asn1/0x00.crt b/tests/asn1/0x00.crt
new file mode 100644
index 000000000..d7eec225c
Binary files /dev/null and b/tests/asn1/0x00.crt differ
diff --git a/tests/asn1/0x80.crt b/tests/asn1/0x80.crt
new file mode 100644
index 000000000..e663829b4
Binary files /dev/null and b/tests/asn1/0x80.crt differ
diff --git a/tests/asn1/0xff.crt b/tests/asn1/0xff.crt
new file mode 100644
index 000000000..f1894296b
Binary files /dev/null and b/tests/asn1/0xff.crt differ
diff --git a/tests/asn1/illegal_padding1.crt b/tests/asn1/illegal_padding1.crt
new file mode 100644
index 000000000..5e1315ae9
Binary files /dev/null and b/tests/asn1/illegal_padding1.crt differ
diff --git a/tests/asn1/illegal_padding2.crt b/tests/asn1/illegal_padding2.crt
new file mode 100644
index 000000000..e5fbb6a5e
Binary files /dev/null and b/tests/asn1/illegal_padding2.crt differ
diff --git a/tests/asn1/illegal_padding3.crt b/tests/asn1/illegal_padding3.crt
new file mode 100644
index 000000000..1a9b098e1
Binary files /dev/null and b/tests/asn1/illegal_padding3.crt differ
diff --git a/tests/asn1/oid_overflow_test.der b/tests/asn1/oid_overflow_test.der
new file mode 100644
index 000000000..99a24d56d
Binary files /dev/null and b/tests/asn1/oid_overflow_test.der differ
diff --git a/tests/asn1/oid_size_test.der b/tests/asn1/oid_size_test.der
new file mode 100644
index 000000000..52d382aa4
Binary files /dev/null and b/tests/asn1/oid_size_test.der differ
diff --git a/tests/asn1/private.der b/tests/asn1/private.der
new file mode 100644
index 000000000..f9ac5ef87
Binary files /dev/null and b/tests/asn1/private.der differ
diff --git a/tests/asn1/root-ca.der b/tests/asn1/root-ca.der
new file mode 100644
index 000000000..9d40cc074
Binary files /dev/null and b/tests/asn1/root-ca.der differ
diff --git a/tests/asn1/type0x08.crt b/tests/asn1/type0x08.crt
new file mode 100644
index 000000000..35b516ca8
Binary files /dev/null and b/tests/asn1/type0x08.crt differ
diff --git a/tests/der_test.c b/tests/der_test.c
index bfc52183f..b5172b44b 100644
--- a/tests/der_test.c
+++ b/tests/der_test.c
@@ -17,6 +17,10 @@ int der_test(void)
#else
+#include
+#include
+#include
+
static const unsigned char _der_tests_stinky_root_cert[] =
"MIIFETCCA/mgAwIBAgIQbv53JNmv518t5lkCHE272jANBgkqhkiG9w0BAQUFADCB"
"lTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug"
@@ -259,6 +263,8 @@ static void _der_tests_print_flexi(ltc_asn1_list* l, unsigned int level)
break;
case LTC_ASN1_INTEGER:
name = "INTEGER";
+ mp_toradix(l->data, buf, 10);
+ text = buf;
break;
case LTC_ASN1_SHORT_INTEGER:
name = "SHORT INTEGER";
@@ -374,37 +380,22 @@ static void _der_tests_print_flexi(ltc_asn1_list* l, unsigned int level)
name = "TELETEX STRING";
text = l->data;
break;
- case LTC_ASN1_CONSTRUCTED:
- if (l->used & 0x80)
- name = "CONTEXT SPECIFIC";
- else
- name = "CONSTRUCTED";
- snprintf(buf, sizeof(buf), "[%d]", l->used & 0x1f);
- text = buf;
- break;
- case LTC_ASN1_CONTEXT_SPECIFIC:
- name = "CONTEXT SPECIFIC";
+ case LTC_ASN1_CUSTOM_TYPE:
+ name = "NON STANDARD";
{
- int r;
- char* s = buf;
- int sz = sizeof(buf);
- r = snprintf(s, sz, "[%d] ", l->used & 0x1f);
- if (r < 0 || r >= sz) {
- printf("Context Specific boom");
- exit(EXIT_FAILURE);
- }
- s += r;
- sz -= r;
- for (n = 0; n < l->size; ++n) {
- r = snprintf(s, sz, "%02X", ((unsigned char*)l->data)[n]);
- if (r < 0 || r >= sz) {
- printf("Context Specific boom");
- exit(EXIT_FAILURE);
- }
- s += r;
- sz -= r;
- }
- text = buf;
+ int r;
+ char* s = buf;
+ int sz = sizeof(buf);
+
+ r = snprintf(s, sz, "[%s %s %llu]", der_asn1_class_to_string_map[l->class], der_asn1_pc_to_string_map[l->pc], l->tag);
+ if (r < 0 || r >= sz) {
+ fprintf(stderr, "%s boom\n", name);
+ exit(EXIT_FAILURE);
+ }
+ s += r;
+ sz -= r;
+
+ text = buf;
}
break;
}
@@ -488,7 +479,7 @@ SEQUENCE(3 elem)
INTEGER 2
*/
- CHECK_ASN1_TYPE(l1, LTC_ASN1_CONSTRUCTED);
+ CHECK_ASN1_TYPE(l1, LTC_ASN1_CUSTOM_TYPE);
CHECK_ASN1_HAS_CHILD(l1);
CHECK_ASN1_HAS_NEXT(l1);
@@ -1028,11 +1019,13 @@ static void der_flexi_test(void)
}
-static int der_choice_test(void)
+static int der_choice_n_custom_test(void)
{
- ltc_asn1_list types[7], host[1];
- unsigned char bitbuf[10], octetbuf[10], ia5buf[10], printbuf[10], outbuf[256], x, y;
- unsigned long integer, oidbuf[10], outlen, inlen;
+ ltc_asn1_list types[10], host[1], custom[1], root[1], child[1];
+ int boolean[1];
+ unsigned char bitbuf[10], octetbuf[10], ia5buf[10], printbuf[10], outbuf[256], custbuf[256], x, y;
+ wchar_t utf8buf[10];
+ unsigned long integer, oidbuf[10], outlen, custlen, inlen, n;
void *mpinteger;
ltc_utctime utctime = { 91, 5, 6, 16, 45, 40, 1, 7, 0 };
ltc_generalizedtime gtime = { 2038, 01, 19, 3, 14, 8, 0, 0, 0, 0 };
@@ -1042,54 +1035,543 @@ static int der_choice_test(void)
for (x = 0; x < sizeof(octetbuf); x++) { octetbuf[x] = x; }
for (x = 0; x < sizeof(ia5buf); x++) { ia5buf[x] = 'a'; }
for (x = 0; x < sizeof(printbuf); x++) { printbuf[x] = 'a'; }
+ for (x = 0; x < sizeof(utf8buf)/sizeof(utf8buf[0]); x++) { utf8buf[x] = L'a'; }
integer = 1;
+ boolean[0] = 1;
for (x = 0; x < sizeof(oidbuf)/sizeof(oidbuf[0]); x++) { oidbuf[x] = x + 1; }
DO(mp_init(&mpinteger));
- for (x = 0; x < 14; x++) {
+ n = sizeof(types)/sizeof(types[0]);
+ for (x = 0; x < n * 2; x++) {
/* setup list */
- LTC_SET_ASN1(types, 0, LTC_ASN1_PRINTABLE_STRING, printbuf, sizeof(printbuf));
- LTC_SET_ASN1(types, 1, LTC_ASN1_BIT_STRING, bitbuf, sizeof(bitbuf));
- LTC_SET_ASN1(types, 2, LTC_ASN1_OCTET_STRING, octetbuf, sizeof(octetbuf));
- LTC_SET_ASN1(types, 3, LTC_ASN1_IA5_STRING, ia5buf, sizeof(ia5buf));
- if (x > 7) {
- LTC_SET_ASN1(types, 4, LTC_ASN1_SHORT_INTEGER, &integer, 1);
+ y = 0;
+ LTC_SET_ASN1(types, y++, LTC_ASN1_PRINTABLE_STRING, printbuf, sizeof(printbuf));
+ if (x > n) {
+ LTC_SET_ASN1(types, y++, LTC_ASN1_BIT_STRING, bitbuf, sizeof(bitbuf));
} else {
- LTC_SET_ASN1(types, 4, LTC_ASN1_INTEGER, mpinteger, 1);
+ LTC_SET_ASN1(types, y++, LTC_ASN1_RAW_BIT_STRING, bitbuf, sizeof(bitbuf));
}
- LTC_SET_ASN1(types, 5, LTC_ASN1_OBJECT_IDENTIFIER, oidbuf, sizeof(oidbuf)/sizeof(oidbuf[0]));
- if (x > 7) {
- LTC_SET_ASN1(types, 6, LTC_ASN1_UTCTIME, &utctime, 1);
+ LTC_SET_ASN1(types, y++, LTC_ASN1_OCTET_STRING, octetbuf, sizeof(octetbuf));
+ LTC_SET_ASN1(types, y++, LTC_ASN1_IA5_STRING, ia5buf, sizeof(ia5buf));
+ LTC_SET_ASN1(types, y++, LTC_ASN1_BOOLEAN, boolean, sizeof(boolean)/sizeof(boolean[0]));
+ if (x > n) {
+ LTC_SET_ASN1(types, y++, LTC_ASN1_SHORT_INTEGER, &integer, 1);
} else {
- LTC_SET_ASN1(types, 6, LTC_ASN1_GENERALIZEDTIME, >ime, 1);
+ LTC_SET_ASN1(types, y++, LTC_ASN1_INTEGER, mpinteger, 1);
}
+ LTC_SET_ASN1(types, y++, LTC_ASN1_OBJECT_IDENTIFIER, oidbuf, sizeof(oidbuf)/sizeof(oidbuf[0]));
+ if (x > n) {
+ LTC_SET_ASN1(types, y++, LTC_ASN1_UTCTIME, &utctime, 1);
+ } else {
+ LTC_SET_ASN1(types, y++, LTC_ASN1_GENERALIZEDTIME, >ime, 1);
+ }
+
+ LTC_SET_ASN1(custom, 0, LTC_ASN1_NULL, NULL, 0);
+ LTC_SET_ASN1_CUSTOM_CONSTRUCTED(types, y++, LTC_ASN1_CL_CONTEXT_SPECIFIC, 0, custom);
- LTC_SET_ASN1(host, 0, LTC_ASN1_CHOICE, types, 7);
+ LTC_SET_ASN1(types, y++, LTC_ASN1_UTF8_STRING, utf8buf, sizeof(utf8buf)/sizeof(utf8buf[0]));
+
+ LTC_SET_ASN1(host, 0, LTC_ASN1_CHOICE, types, n);
/* encode */
outlen = sizeof(outbuf);
- DO(der_encode_sequence(&types[x>6?x-7:x], 1, outbuf, &outlen));
+ DO(der_encode_sequence(&types[x % n], 1, outbuf, &outlen));
+
+ /* custom encode */
+ child[0] = types[x % n];
+ if (x < n) {
+ LTC_SET_ASN1_CUSTOM_CONSTRUCTED(root, 0, LTC_ASN1_CL_CONTEXT_SPECIFIC, 1U << (x % n), child);
+ } else {
+ LTC_SET_ASN1_CUSTOM_PRIMITIVE(root, 0, LTC_ASN1_CL_CONTEXT_SPECIFIC, 1U << (x % n), child->type, child->data, child->size);
+ }
+ custlen = sizeof(custbuf);
+ /* don't try to custom-encode a primitive custom-type */
+ if (child[0].type != LTC_ASN1_CUSTOM_TYPE || root->pc != LTC_ASN1_PC_PRIMITIVE) {
+ DO(der_encode_custom_type(root, custbuf, &custlen));
+ }
/* decode it */
inlen = outlen;
- DO(der_decode_sequence(outbuf, inlen, &host[0], 1));
+ DO(der_decode_sequence(outbuf, inlen, host, 1));
- for (y = 0; y < 7; y++) {
- if (types[y].used && y != (x>6?x-7:x)) {
+ for (y = 0; y < n; y++) {
+ if (types[y].used && y != (x % n)) {
fprintf(stderr, "CHOICE, flag %u in trial %u was incorrectly set to one\n", y, x);
return 1;
}
- if (!types[y].used && y == (x>6?x-7:x)) {
+ if (!types[y].used && y == (x % n)) {
fprintf(stderr, "CHOICE, flag %u in trial %u was incorrectly set to zero\n", y, x);
return 1;
}
}
+
+ /* custom decode */
+ if (child[0].type != LTC_ASN1_CUSTOM_TYPE || root->pc != LTC_ASN1_PC_PRIMITIVE) {
+ DO(der_decode_custom_type(custbuf, custlen, root));
+ }
}
mp_clear(mpinteger);
return 0;
}
+static void _der_decode_print(const void* p, unsigned long* plen)
+{
+ ltc_asn1_list *list;
+ DO(der_decode_sequence_flexi(p, plen, &list));
+#ifdef LTC_DER_TESTS_PRINT_FLEXI
+ fprintf(stderr, "\n\n");
+ _der_tests_print_flexi(list, 0);
+ fprintf(stderr, "\n\n");
+#endif
+ der_sequence_free(list);
+}
+
+static const unsigned char eckey_privc_der[] = {
+ 0x30, 0x81, 0xf0, 0x02, 0x01, 0x01, 0x04, 0x18, 0x96, 0x9d, 0x28, 0xf2, 0x40, 0x48, 0x19, 0x11,
+ 0x79, 0xb0, 0x47, 0x8e, 0x8c, 0x6b, 0x3d, 0x9b, 0xf2, 0x31, 0x16, 0x10, 0x08, 0x72, 0xb1, 0x86,
+ 0xa0, 0x81, 0xb2, 0x30, 0x81, 0xaf, 0x02, 0x01, 0x01, 0x30, 0x24, 0x06, 0x07, 0x2a, 0x86, 0x48,
+ 0xce, 0x3d, 0x01, 0x01, 0x02, 0x19, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x30,
+ 0x4b, 0x04, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x04, 0x18, 0x22, 0x12, 0x3d,
+ 0xc2, 0x39, 0x5a, 0x05, 0xca, 0xa7, 0x42, 0x3d, 0xae, 0xcc, 0xc9, 0x47, 0x60, 0xa7, 0xd4, 0x62,
+ 0x25, 0x6b, 0xd5, 0x69, 0x16, 0x03, 0x15, 0x00, 0xc4, 0x69, 0x68, 0x44, 0x35, 0xde, 0xb3, 0x78,
+ 0xc4, 0xb6, 0x5c, 0xa9, 0x59, 0x1e, 0x2a, 0x57, 0x63, 0x05, 0x9a, 0x2e, 0x04, 0x19, 0x02, 0x7d,
+ 0x29, 0x77, 0x81, 0x00, 0xc6, 0x5a, 0x1d, 0xa1, 0x78, 0x37, 0x16, 0x58, 0x8d, 0xce, 0x2b, 0x8b,
+ 0x4a, 0xee, 0x8e, 0x22, 0x8f, 0x18, 0x96, 0x02, 0x19, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7a, 0x62, 0xd0, 0x31, 0xc8, 0x3f, 0x42, 0x94, 0xf6, 0x40,
+ 0xec, 0x13, 0x02, 0x01, 0x01, 0xa1, 0x1c, 0x03, 0x1a, 0x00, 0x02, 0x55, 0x2c, 0xb8, 0x73, 0x5c,
+ 0x9d, 0x98, 0xe4, 0x57, 0xfe, 0xd5, 0x96, 0x0a, 0x73, 0x8d, 0x82, 0xd7, 0xce, 0x05, 0xa9, 0x79,
+ 0x91, 0x5c, 0xf9
+};
+
+static const unsigned char eckey_privs_der[] = {
+ 0x30, 0x50, 0x02, 0x01, 0x01, 0x04, 0x14, 0x82, 0xef, 0x42, 0x0b, 0xc7, 0xe2, 0x9f, 0x3a, 0x84,
+ 0xe5, 0x74, 0xec, 0x9c, 0xc5, 0x10, 0x26, 0x63, 0x8d, 0xb5, 0x46, 0xa0, 0x07, 0x06, 0x05, 0x2b,
+ 0x81, 0x04, 0x00, 0x09, 0xa1, 0x2c, 0x03, 0x2a, 0x00, 0x04, 0xb5, 0xb1, 0x5a, 0xb0, 0x2a, 0x10,
+ 0xd1, 0xf5, 0x4d, 0x6a, 0x41, 0xde, 0xcd, 0x69, 0x09, 0xb3, 0x5f, 0x26, 0xb0, 0xa2, 0xaf, 0xd3,
+ 0x02, 0x89, 0x5e, 0xd4, 0x96, 0x5c, 0xbc, 0x2a, 0x7e, 0x75, 0x85, 0x86, 0x29, 0xb3, 0x29, 0x13,
+ 0x77, 0xc3
+};
+static void der_custom_test(void)
+{
+ ltc_asn1_list bool_ean[1], seq1[1], custom[1];
+ int boolean;
+ unsigned long len;
+ unsigned char buf[1024];
+ unsigned char buf1[] = { 0xbf, 0xa0, 0x00, 0x04, 0x30, 0x02, 0x05, 0x00 };
+ unsigned char buf2[] = { 0x30, 0x08, 0xbf, 0xa0, 0x00, 0x04, 0x30, 0x02, 0x05, 0x00 };
+
+ boolean = 0x1;
+ LTC_SET_ASN1(bool_ean, 0, LTC_ASN1_BOOLEAN, &boolean, 1);
+ LTC_SET_ASN1(seq1, 0, LTC_ASN1_SEQUENCE, bool_ean, 1);
+ LTC_SET_ASN1_CUSTOM_CONSTRUCTED(custom, 0, LTC_ASN1_CL_CONTEXT_SPECIFIC, 0x1000, seq1);
+
+ DO(der_length_custom_type(custom, &len, NULL));
+ len = sizeof(buf);
+ DO(der_encode_custom_type(custom, buf, &len));
+ _der_decode_print(buf, &len);
+
+ boolean = 0x0;
+ DO(der_decode_custom_type(buf, len, custom));
+
+ DO(der_length_sequence(custom, 1, &len));
+ len = sizeof(buf);
+ DO(der_encode_sequence(custom, 1, buf, &len));
+ _der_decode_print(buf, &len);
+
+ boolean = 0x0;
+ DO(der_decode_sequence(buf, len, custom, 1));
+
+ LTC_SET_ASN1_CUSTOM_PRIMITIVE(bool_ean, 0, LTC_ASN1_CL_CONTEXT_SPECIFIC, 0x8000, LTC_ASN1_BOOLEAN, &boolean, 1);
+ DO(der_length_custom_type(bool_ean, &len, NULL));
+ len = sizeof(buf);
+ DO(der_encode_custom_type(bool_ean, buf, &len));
+ _der_decode_print(buf, &len);
+
+ LTC_SET_ASN1_CUSTOM_PRIMITIVE(bool_ean, 0, LTC_ASN1_CL_CONTEXT_SPECIFIC, 0x8000, LTC_ASN1_BOOLEAN, &boolean, 1);
+ DO(der_decode_custom_type(buf, len, bool_ean));
+
+ len = sizeof(buf1);
+ _der_decode_print(buf1, &len);
+
+ len = sizeof(buf2);
+ _der_decode_print(buf2, &len);
+
+ len = sizeof(eckey_privc_der);
+ _der_decode_print(eckey_privc_der, &len);
+
+ len = sizeof(eckey_privs_der);
+ _der_decode_print(eckey_privs_der, &len);
+}
+
+typedef int (*_der_Xcode)(const void*, unsigned long, void*, unsigned long*);
+
+typedef struct {
+ _der_Xcode encode;
+ _der_Xcode decode;
+ const void* in;
+ size_t in_sz;
+ size_t factor;
+ size_t type_sz;
+ const char* what;
+} der_Xcode_t;
+
+static void der_Xcode_run(const der_Xcode_t* x)
+{
+ unsigned long l1, l2, sz;
+ void *d1, *d2;
+ int err;
+
+ l1 = 1;
+ d1 = XMALLOC(l1 * x->type_sz);
+ sz = (x->in_sz * x->factor)/x->type_sz;
+
+ if ((err = x->encode(x->in, sz, d1, &l1)) == CRYPT_BUFFER_OVERFLOW) {
+ d1 = XREALLOC(d1, l1 * x->type_sz);
+ }
+ DO(x->encode(x->in, sz, d1, &l1));
+ l2 = 1;
+ d2 = XMALLOC(l2 * x->type_sz);
+ while ((err = x->decode(d1, l1, d2, &l2)) == CRYPT_BUFFER_OVERFLOW) {
+ d2 = XREALLOC(d2, l2 * x->type_sz);
+ }
+ DO(x->decode(d1, l1, d2, &l2));
+ DO(compare_testvector(d2, (l2/x->factor) * x->type_sz, x->in, x->in_sz, x->what, __LINE__) == 0 ? CRYPT_OK : CRYPT_FAIL_TESTVECTOR);
+ XFREE(d2);
+ XFREE(d1);
+}
+
+#define DER_XCODE_X(n, b, x) { \
+ (_der_Xcode)der_encode_ ## n, \
+ (_der_Xcode)der_decode_ ## n, \
+ b, \
+ sizeof(b), \
+ x, \
+ sizeof(typeof(b[0])),\
+ #n \
+}
+
+#define DER_XCODE(n, b) DER_XCODE_X(n, b, 1)
+
+static void der_Xcode_test(void)
+{
+ unsigned long i;
+ ltc_asn1_list *list;
+ ltc_asn1_list ttex_neg_int[2];
+ unsigned char buf[128];
+ void* mpinteger;
+ const unsigned long oid[3] = { 1, 23, 42 };
+ const unsigned char bit_string[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
+ const unsigned char multi_buf[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ const char multi_string[] = {'l','i','b','t','o','m','c','r','y','p','t'};
+ const wchar_t wchar_string[] = L"libtomcrypt";
+
+ const unsigned char teletex_neg_int[] = { 0x30, 0x11, 0x14, 0x0b, 0x6c, 0x69, 0x62, 0x74,
+ 0x6f, 0x6d, 0x63, 0x72, 0x79, 0x70, 0x74, 0x02,
+ 0x02, 0xfc, 0x19 };
+
+ const der_Xcode_t xcode_tests[] =
+ {
+ DER_XCODE(bit_string, bit_string),
+ DER_XCODE_X(raw_bit_string, multi_buf, 8),
+ DER_XCODE(octet_string, multi_buf),
+ DER_XCODE(object_identifier, oid),
+ DER_XCODE(ia5_string, multi_string),
+ DER_XCODE(printable_string, multi_string),
+ DER_XCODE(utf8_string, wchar_string),
+ };
+
+ for (i = 0; i < sizeof(xcode_tests)/sizeof(xcode_tests[0]); ++i) {
+ der_Xcode_run(&xcode_tests[i]);
+ }
+
+ i = sizeof(teletex_neg_int);
+ DO(der_decode_sequence_flexi(teletex_neg_int, &i, &list));
+#ifdef LTC_DER_TESTS_PRINT_FLEXI
+ fprintf(stderr, "\n\n");
+ _der_tests_print_flexi(list, 0);
+ fprintf(stderr, "\n\n");
+#endif
+ if (list->child == NULL || list->child->next == NULL)
+ exit(EXIT_FAILURE);
+ ttex_neg_int[0] = *list->child->next;
+ i = sizeof(buf);
+ DO(der_encode_sequence(ttex_neg_int, 1, buf, &i));
+ der_sequence_free(list);
+
+ DO(mp_init(&mpinteger));
+ LTC_SET_ASN1(ttex_neg_int, 0, LTC_ASN1_TELETEX_STRING, buf, sizeof(buf));
+ LTC_SET_ASN1(ttex_neg_int, 1, LTC_ASN1_INTEGER, mpinteger, 1);
+
+ DO(der_decode_sequence(teletex_neg_int, sizeof(teletex_neg_int), ttex_neg_int, 2));
+
+ mp_clear(mpinteger);
+}
+
+static off_t fsize(const char *filename)
+{
+ struct stat st;
+
+ if (stat(filename, &st) == 0) return st.st_size;
+
+ return -1;
+}
+
+static void der_asn1_test(void)
+{
+ DIR *d = opendir("tests/asn1");
+ struct dirent *de;
+ char fname[PATH_MAX];
+ void* buf = NULL;
+ FILE *f = NULL;
+ off_t fsz;
+ unsigned long sz;
+ ltc_asn1_list *list;
+ int err;
+ if (d == NULL)
+ return;
+ while((de = readdir(d)) != NULL) {
+ fname[0] = '\0';
+ if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+ continue;
+ strcat(fname, "tests/asn1/");
+ strcat(fname, de->d_name);
+ fsz = fsize(fname);
+ if (fsz == -1)
+ break;
+#if defined(LTC_TEST_DBG) && LTC_TEST_DBG > 1
+ fprintf(stderr, "Try to decode %s\n", fname);
+#endif
+ f = fopen(fname, "rb");
+ sz = fsz;
+ buf = XMALLOC(fsz);
+ if (fread(buf, 1, sz, f) != sz)
+ break;
+
+ if ((err = der_decode_sequence_flexi(buf, &sz, &list)) == CRYPT_OK) {
+#ifdef LTC_DER_TESTS_PRINT_FLEXI
+ fprintf(stderr, "\n\n");
+ _der_tests_print_flexi(list, 0);
+ fprintf(stderr, "\n\n");
+#endif
+ der_sequence_free(list);
+ } else {
+#if defined(LTC_TEST_DBG)
+ fprintf(stderr, "Could not decode %s: %s\n\n", fname, error_to_string(err));
+#endif
+ }
+ XFREE(buf);
+ buf = NULL;
+ fclose(f);
+ f = NULL;
+ }
+ if (buf != NULL) XFREE(buf);
+ if (f != NULL) fclose(f);
+ closedir(d);
+}
+
+
+static void _der_regression_test(void)
+{
+ static const unsigned char _broken_sequence[] = {
+ 0x30,0x41,0x02,0x84,0x7f,0xff,0xff,0xff,0x1e,0x41,0xb4,0x79,0xad,0x57,0x69,
+ 0x05,0xb9,0x60,0xfe,0x14,0xea,0xdb,0x91,0xb0,0xcc,0xf3,0x48,0x43,0xda,0xb9,
+ 0x16,0x17,0x3b,0xb8,0xc9,0xcd,0x02,0x1d,0x00,0xad,0xe6,0x59,0x88,0xd2,0x37,
+ 0xd3,0x0f,0x9e,0xf4,0x1d,0xd4,0x24,0xa4,0xe1,0xc8,0xf1,0x69,0x67,0xcf,0x33,
+ 0x65,0x81,0x3f,0xe8,0x78,0x62,0x36
+ };
+ static const unsigned char _addtl_bytes[] = {
+ 0x30,0x45,0x02,0x21,0x00,0xb7,0xba,0xba,0xe9,0x33,0x2b,0x54,0xb8,0xa3,0xa0,0x5b,0x70,0x04,0x57,
+ 0x98,0x21,0xa8,0x87,0xa1,0xb2,0x14,0x65,0xf7,0xdb,0x8a,0x3d,0x49,0x1b,0x39,0xfd,0x2c,0x3f,0x02,
+ 0x20,0x74,0x72,0x91,0xdd,0x2f,0x3f,0x44,0xaf,0x7a,0xce,0x68,0xea,0x33,0x43,0x1d,0x6f,0x94,0xe4,
+ 0x18,0xc1,0x06,0xa6,0xe7,0x62,0x85,0xcd,0x59,0xf4,0x32,0x60,0xec,0xce,0x00,0x00
+ };
+ unsigned long len;
+ void *x, *y;
+ ltc_asn1_list seq[2];
+ mp_init_multi(&x, &y, NULL);
+ LTC_SET_ASN1(seq, 0, LTC_ASN1_INTEGER, x, 1UL);
+ LTC_SET_ASN1(seq, 1, LTC_ASN1_INTEGER, y, 1UL);
+ DO(der_decode_sequence(_broken_sequence, sizeof(_broken_sequence), seq, 2) != CRYPT_OK ? CRYPT_OK : CRYPT_FAIL_TESTVECTOR);
+ mp_cleanup_multi(&y, &x, NULL);
+ len = sizeof(_broken_sequence);
+
+ mp_init_multi(&x, &y, NULL);
+ LTC_SET_ASN1(seq, 0, LTC_ASN1_INTEGER, x, 1UL);
+ LTC_SET_ASN1(seq, 1, LTC_ASN1_INTEGER, y, 1UL);
+ DO(der_decode_sequence(_addtl_bytes, sizeof(_addtl_bytes), seq, 2) == CRYPT_INPUT_TOO_LONG ? CRYPT_OK : CRYPT_FAIL_TESTVECTOR);
+ mp_cleanup_multi(&y, &x, NULL);
+ len = sizeof(_addtl_bytes);
+ _der_decode_print(_addtl_bytes, &len);
+}
+
+static void der_toolong_test(void)
+{
+ int n, err, failed = 0;
+ ltc_asn1_list *list;
+ unsigned long len, oid[16];
+ unsigned char buf5[5], buf12[12], buf32[32];
+ static const unsigned char invalid1[] = {
+ 0x30,0x19, /* SEQUENCE len=25 bytes */
+ 0x30,0x0a, /* SEQUENCE len=10 bytes (which is wrong, should be 9) */
+ 0x04,0x05, /* OCTET STRING len=5 */ 0x2b,0x0e,0x03,0x02,0x1a,
+ 0x05,0x00, /* NULL */
+ 0x04,0x0c, /* OCTET STRING len=12 */ 0xf7,0xff,0x9e,0x8b,0x7b,0xb2,0xe0,0x9b,0x70,0x93,0x5a,0x5d,
+ };
+ static const unsigned char invalid2[] = {
+ 0x30,0x0d, /* SEQUENCE len=13 bytes*/
+ 0x02,0x05, /* INTEGER len=5 */ 0x00,0xb7,0xba,0xba,0xe9,
+ 0x02,0x04, /* INTEGER len=4 */ 0x74,0x72,0x91,0xdd,
+ 0x00,0x00 /* garbage after the sequence, der_decode_sequence_flexi should ignore this */
+ };
+ static const unsigned char invalid3[] = {
+ 0x30,0x0f, /* SEQUENCE len=15 bytes*/
+ 0x02,0x05, /* INTEGER len=5 */ 0x00,0xb7,0xba,0xba,0xe9,
+ 0x02,0x04, /* INTEGER len=4 */ 0x74,0x72,0x91,0xdd,
+ 0x00,0x00 /* garbage inside the sequence */
+ };
+ static const unsigned char invalid4[] = {
+ 0x30, 0x30,
+ 0x30, 0x0d,
+ 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
+ 0x05, 0x00,
+ 0x04, 0x20, 0x53, 0x2e, 0xaa, 0xbd, 0x95, 0x74, 0x88, 0x0d, 0xbf, 0x76, 0xb9, 0xb8, 0xcc, 0x00, 0x83, 0x2c,
+ 0x20, 0xa6, 0xec, 0x11, 0x3d, 0x68, 0x22, 0x99, 0x55, 0x0d, 0x7a, 0x6e, 0x0f, 0x34, 0x5e, 0x25
+
+ };
+ static const unsigned char invalid5[] = {
+ 0x30, 0x31,
+ 0x30, 0x0e,
+ 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
+ 0x05, 0x00,
+ 0x04, 0x20, 0x53, 0x2e, 0xaa, 0xbd, 0x95,0x74, 0x88, 0x0d, 0xbf, 0x76, 0xb9, 0xb8, 0xcc,0x00, 0x83, 0x2c,
+ 0x20, 0xa6, 0xec, 0x11, 0x3d,0x68, 0x22, 0x99, 0x55, 0x0d, 0x7a, 0x6e, 0x0f,0x34, 0x5e, 0x25
+
+ };
+ static const unsigned char invalid6[] = {
+ 0x30, 0x31,
+ 0x30, 0x0c,
+ 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
+ 0x05, 0x00,
+ 0x04, 0x20, 0x53, 0x2e, 0xaa, 0xbd, 0x95,0x74, 0x88, 0x0d, 0xbf, 0x76, 0xb9, 0xb8, 0xcc,0x00, 0x83, 0x2c,
+ 0x20, 0xa6, 0xec, 0x11, 0x3d,0x68, 0x22, 0x99, 0x55, 0x0d, 0x7a, 0x6e, 0x0f,0x34, 0x5e, 0x25
+
+ };
+
+ ltc_asn1_list seqsub[2], seqoid[2], seqmain[2], seqint[2];
+ void *int1, *int2;
+
+ LTC_SET_ASN1(seqsub, 0, LTC_ASN1_OCTET_STRING, buf5, 5);
+ LTC_SET_ASN1(seqsub, 1, LTC_ASN1_NULL, NULL, 0);
+ LTC_SET_ASN1(seqmain, 0, LTC_ASN1_SEQUENCE, seqsub, 2);
+ LTC_SET_ASN1(seqmain, 1, LTC_ASN1_OCTET_STRING, buf12, 12);
+
+ n = 1;
+ len = sizeof(invalid1);
+ err = der_decode_sequence_strict(invalid1, len, seqmain, 2);
+ if (err == CRYPT_OK) {
+ fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence\n", n);
+ failed = 1;
+ }
+ len = sizeof(invalid1);
+ err = der_decode_sequence_flexi(invalid1, &len, &list);
+ if (err == CRYPT_OK) {
+ fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence_flexi\n", n);
+ failed = 1;
+ der_sequence_free(list);
+ }
+
+ mp_init_multi(&int1, &int2, NULL);
+ LTC_SET_ASN1(seqint, 0, LTC_ASN1_INTEGER, int1, 1);
+ LTC_SET_ASN1(seqint, 1, LTC_ASN1_INTEGER, int2, 1);
+
+ n++;
+ len = sizeof(invalid2);
+ err = der_decode_sequence_strict(invalid2, len, seqint, 2);
+ if (err == CRYPT_OK) {
+ fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence\n", n);
+ failed = 1;
+ }
+ len = sizeof(invalid2);
+ err = der_decode_sequence_flexi(invalid2, &len, &list);
+ /* flexi parser should decode this; however returning "len" shorter than "sizeof(invalid2)" */
+ if (err != CRYPT_OK || len != 15) {
+ fprintf(stderr,"der_decode_sequence_flexi failed, err=%d (expected 0) len=%lu (expected 15)\n", err, len);
+ failed = 1;
+ }
+ if (err == CRYPT_OK)
+ der_sequence_free(list);
+
+ n++;
+ len = sizeof(invalid3);
+ err = der_decode_sequence_strict(invalid3, len, seqint, 2);
+ if (err == CRYPT_OK) {
+ fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence\n", n);
+ failed = 1;
+ }
+ len = sizeof(invalid3);
+ err = der_decode_sequence_flexi(invalid3, &len, &list);
+ if (err == CRYPT_OK) {
+ fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence_flexi\n", n);
+ failed = 1;
+ der_sequence_free(list);
+ }
+
+ mp_clear_multi(int1, int2, NULL);
+
+ LTC_SET_ASN1(seqoid, 0, LTC_ASN1_OBJECT_IDENTIFIER, oid, sizeof(oid)/sizeof(oid[0]));
+ LTC_SET_ASN1(seqoid, 1, LTC_ASN1_NULL, NULL, 0);
+ LTC_SET_ASN1(seqmain, 0, LTC_ASN1_SEQUENCE, seqoid, 2);
+ LTC_SET_ASN1(seqmain, 1, LTC_ASN1_OCTET_STRING, buf32, 32);
+
+ n++;
+ len = sizeof(invalid4);
+ err = der_decode_sequence_strict(invalid4, len, seqmain, 2);
+ if (err == CRYPT_OK) {
+ fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence\n", n);
+ failed = 1;
+ }
+ len = sizeof(invalid4);
+ err = der_decode_sequence_flexi(invalid4, &len, &list);
+ if (err == CRYPT_OK) {
+ fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence_flexi\n", n);
+ failed = 1;
+ der_sequence_free(list);
+ }
+
+ n++;
+ len = sizeof(invalid5);
+ err = der_decode_sequence_strict(invalid5, len, seqmain, 2);
+ if (err == CRYPT_OK) {
+ fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence\n", n);
+ failed = 1;
+ }
+ len = sizeof(invalid5);
+ err = der_decode_sequence_flexi(invalid5, &len, &list);
+ if (err == CRYPT_OK) {
+ fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence_flexi\n", n);
+ failed = 1;
+ der_sequence_free(list);
+ }
+ n++;
+ len = sizeof(invalid6);
+ err = der_decode_sequence_strict(invalid6, len, seqmain, 2);
+ if (err == CRYPT_OK) {
+ fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence\n", n);
+ failed = 1;
+ }
+ len = sizeof(invalid6);
+ err = der_decode_sequence_flexi(invalid6, &len, &list);
+ if (err == CRYPT_OK) {
+ fprintf(stderr,"Sequence invalid%d accepted by der_decode_sequence_flexi\n", n);
+ failed = 1;
+ der_sequence_free(list);
+ }
+
+ if (failed) exit(EXIT_FAILURE);
+}
int der_test(void)
{
@@ -1125,8 +1607,39 @@ int der_test(void)
if (ltc_mp.name == NULL) return CRYPT_NOP;
+ der_Xcode_test();
+
+ der_asn1_test();
+
+ der_custom_test();
+
+ _der_regression_test();
+
+ der_toolong_test();
+
der_cacert_test();
+ y = 0xffffff00;
+#if ULONG_MAX == ULLONG_MAX
+ y <<= 32;
+#endif
+ while (y != 0) {
+ /* we have to modify x to be larger than the encoded
+ * length as der_decode_asn1_length() checks also if
+ * the encoded length is reasonable in regards to the
+ * available buffer size.
+ */
+ x = sizeof(buf[0]);
+ DO(der_encode_asn1_length(y, buf[0], &x));
+ x = y + x;
+ DO(der_decode_asn1_length(buf[0], &x, &z));
+ if (y != z) {
+ fprintf(stderr, "Failed to en- or decode length correctly! %lu != %lu\n", y, z);
+ return 1;
+ }
+ y >>= 3;
+ }
+
DO(mp_init_multi(&a, &b, &c, &d, &e, &f, &g, NULL));
for (zz = 0; zz < 16; zz++) {
#ifdef USE_TFM
@@ -1143,7 +1656,7 @@ int der_test(void)
x = sizeof(buf[0]);
DO(der_encode_integer(a, buf[0], &x));
DO(der_length_integer(a, &y));
- if (y != x) { fprintf(stderr, "DER INTEGER size mismatch\n"); return 1; }
+ if (y != x) { fprintf(stderr, "DER INTEGER size mismatch %lu != %lu\n", y, x); return 1; }
mp_set_int(b, 0);
DO(der_decode_integer(buf[0], y, b));
if (y != x || mp_cmp(a, b) != LTC_MP_EQ) {
@@ -1440,7 +1953,7 @@ tmp_time.off_hh);
der_set_test();
der_flexi_test();
- return der_choice_test();
+ return der_choice_n_custom_test();
}
#endif
diff --git a/tests/dsa_test.c b/tests/dsa_test.c
index 67391547f..d26586541 100644
--- a/tests/dsa_test.c
+++ b/tests/dsa_test.c
@@ -306,7 +306,8 @@ static int _dsa_wycheproof_test(void)
}
stat = 666; /* intentionally not one, not zero */
- DO(dsa_verify_hash(sig, sizeof(sig), hash, hashlen, &stat, &key));
+ DOX(dsa_verify_hash(sig, sizeof(sig), hash, hashlen, &stat, &key)
+ == CRYPT_INPUT_TOO_LONG ? CRYPT_OK:CRYPT_INVALID_PACKET, "should be too long");
/* this should be invalid */
if (stat != 0) {
fprintf(stderr, "dsa_verify_hash did not reject invalid signature\n");
diff --git a/tests/rsa/rsa_size_1024_bits.der b/tests/rsa/rsa_size_1024_bits.der
new file mode 100644
index 000000000..63d057324
Binary files /dev/null and b/tests/rsa/rsa_size_1024_bits.der differ
diff --git a/tests/rsa/rsa_size_16384_bits.der b/tests/rsa/rsa_size_16384_bits.der
new file mode 100644
index 000000000..71e64e5cb
Binary files /dev/null and b/tests/rsa/rsa_size_16384_bits.der differ
diff --git a/tests/rsa/rsa_size_1999_bits.der b/tests/rsa/rsa_size_1999_bits.der
new file mode 100644
index 000000000..d2af9922d
Binary files /dev/null and b/tests/rsa/rsa_size_1999_bits.der differ
diff --git a/tests/rsa/rsa_size_2048_bits.der b/tests/rsa/rsa_size_2048_bits.der
new file mode 100644
index 000000000..7aaf80501
Binary files /dev/null and b/tests/rsa/rsa_size_2048_bits.der differ
diff --git a/tests/rsa/rsa_size_4096_bits.der b/tests/rsa/rsa_size_4096_bits.der
new file mode 100644
index 000000000..2e3cc1642
Binary files /dev/null and b/tests/rsa/rsa_size_4096_bits.der differ
diff --git a/tests/rsa/rsa_size_512_bits.der b/tests/rsa/rsa_size_512_bits.der
new file mode 100644
index 000000000..1fe69549f
Binary files /dev/null and b/tests/rsa/rsa_size_512_bits.der differ
diff --git a/tests/rsa/rsa_size_8192_bits.der b/tests/rsa/rsa_size_8192_bits.der
new file mode 100644
index 000000000..faba635d5
Binary files /dev/null and b/tests/rsa/rsa_size_8192_bits.der differ
diff --git a/tests/rsa_test.c b/tests/rsa_test.c
index e6fa8ecac..28ddc554c 100644
--- a/tests/rsa_test.c
+++ b/tests/rsa_test.c
@@ -10,6 +10,10 @@
#if defined(LTC_MRSA)
+#include
+#include
+#include
+
#define RSA_MSGSIZE 78
/* These are test keys [see file test.key] that I use to test my import/export against */
@@ -343,6 +347,76 @@ static int _rsa_issue_301(int prng_idx)
return CRYPT_OK;
}
+static off_t fsize(const char *filename)
+{
+ struct stat st;
+
+ if (stat(filename, &st) == 0) return st.st_size;
+
+ return -1;
+}
+
+static int _rsa_size_test(void)
+{
+ DIR *d = opendir("tests/rsa");
+ struct dirent *de;
+ char fname[PATH_MAX];
+ void* buf = NULL;
+ FILE *f = NULL;
+ off_t fsz;
+ unsigned long sz;
+ int err = CRYPT_FILE_NOTFOUND;
+ rsa_key k;
+ if (d == NULL)
+ return CRYPT_FILE_NOTFOUND;
+ while((de = readdir(d)) != NULL) {
+ fname[0] = '\0';
+ if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+ continue;
+ strcat(fname, "tests/rsa/");
+ strcat(fname, de->d_name);
+ fsz = fsize(fname);
+ if (fsz == -1)
+ break;
+ /* here we use the filesize as indicator for the rsa size
+ * that would fail to import for tfm because it's fixed-size
+ */
+ if ((strcmp(ltc_mp.name, "TomsFastMath") == 0) && (fsz > 2048)) {
+#if defined(LTC_TEST_DBG) && LTC_TEST_DBG > 1
+ fprintf(stderr, "TomsFastMath skip: %s\n", fname);
+#endif
+ continue;
+ }
+#if defined(LTC_TEST_DBG) && LTC_TEST_DBG > 1
+ fprintf(stderr, "Try to import %s\n", fname);
+#endif
+ f = fopen(fname, "rb");
+ sz = fsz;
+ buf = XMALLOC(fsz);
+ if (fread(buf, 1, sz, f) != sz) {
+ err = CRYPT_ERROR;
+ break;
+ }
+
+ if ((err = rsa_import_x509(buf, sz, &k)) == CRYPT_OK) {
+ rsa_free(&k);
+ } else {
+#if defined(LTC_TEST_DBG)
+ fprintf(stderr, "Could not import RSA key of %s: %s\n\n", fname, error_to_string(err));
+#endif
+ break;
+ }
+ XFREE(buf);
+ buf = NULL;
+ fclose(f);
+ f = NULL;
+ }
+ if (buf != NULL) XFREE(buf);
+ if (f != NULL) fclose(f);
+ closedir(d);
+ return err;
+}
+
int rsa_test(void)
{
unsigned char in[1024], out[1024], tmp[3072];
@@ -368,6 +442,8 @@ int rsa_test(void)
return 1;
}
+ DO(_rsa_size_test());
+
DO(_rsa_issue_301(prng_idx));
/* make 10 random key */
@@ -657,11 +733,8 @@ print_hex("q", tmp, len);
len3 = sizeof(tmp);
/* (6) */
- if (i < 8)
- DOX(rsa_verify_hash_ex(p2, len2, p, 20, LTC_PKCS_1_V1_5, hash_idx, -1, &stat, &pubKey)
+ DOX(rsa_verify_hash_ex(p2, len2, p, 20, LTC_PKCS_1_V1_5, hash_idx, -1, &stat, &pubKey)
== CRYPT_INVALID_PACKET ? CRYPT_OK:CRYPT_INVALID_PACKET, "should fail");
- else
- DOX(rsa_verify_hash_ex(p2, len2, p, 20, LTC_PKCS_1_V1_5, hash_idx, -1, &stat, &pubKey), "should succeed");
DOX(stat == 0?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, "should fail");
}
rsa_free(&key);