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);