Gilles Peskine bcbe1dfb23 Improve the documentation of ASN.1 parsing functions
Document preconditions on parameters, values changed through pointers,
and error codes.

This commit leaves some issues regarding integers (especially negative
integers) open, because we don't have a policy decision on how to
handle them yet.
2019-09-11 15:46:44 +02:00

454 lines
18 KiB
C

/**
* \file asn1.h
*
* \brief Generic ASN.1 parsing
*/
/*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_ASN1_H
#define MBEDTLS_ASN1_H
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include <stddef.h>
#if defined(MBEDTLS_BIGNUM_C)
#include "mbedtls/bignum.h"
#endif
/**
* \addtogroup asn1_module
* \{
*/
/**
* \name ASN1 Error codes
* These error codes are OR'ed to X509 error codes for
* higher error granularity.
* ASN1 is a standard to specify data structures.
* \{
*/
#define MBEDTLS_ERR_ASN1_OUT_OF_DATA -0x0060 /**< Out of data when parsing an ASN1 data structure. */
#define MBEDTLS_ERR_ASN1_UNEXPECTED_TAG -0x0062 /**< ASN1 tag was of an unexpected value. */
#define MBEDTLS_ERR_ASN1_INVALID_LENGTH -0x0064 /**< Error when trying to determine the length or invalid length. */
#define MBEDTLS_ERR_ASN1_LENGTH_MISMATCH -0x0066 /**< Actual length differs from expected length. */
#define MBEDTLS_ERR_ASN1_INVALID_DATA -0x0068 /**< Data is invalid. (not used) */
#define MBEDTLS_ERR_ASN1_ALLOC_FAILED -0x006A /**< Memory allocation failed */
#define MBEDTLS_ERR_ASN1_BUF_TOO_SMALL -0x006C /**< Buffer too small when writing ASN.1 data structure. */
/* \} name */
/**
* \name DER constants
* These constants comply with the DER encoded ASN.1 type tags.
* DER encoding uses hexadecimal representation.
* An example DER sequence is:\n
* - 0x02 -- tag indicating INTEGER
* - 0x01 -- length in octets
* - 0x05 -- value
* Such sequences are typically read into Mbed TLS's \c mbedtls_x509_buf.
* \{
*/
#define MBEDTLS_ASN1_BOOLEAN 0x01
#define MBEDTLS_ASN1_INTEGER 0x02
#define MBEDTLS_ASN1_BIT_STRING 0x03
#define MBEDTLS_ASN1_OCTET_STRING 0x04
#define MBEDTLS_ASN1_NULL 0x05
#define MBEDTLS_ASN1_OID 0x06
#define MBEDTLS_ASN1_UTF8_STRING 0x0C
#define MBEDTLS_ASN1_SEQUENCE 0x10
#define MBEDTLS_ASN1_SET 0x11
#define MBEDTLS_ASN1_PRINTABLE_STRING 0x13
#define MBEDTLS_ASN1_T61_STRING 0x14
#define MBEDTLS_ASN1_IA5_STRING 0x16
#define MBEDTLS_ASN1_UTC_TIME 0x17
#define MBEDTLS_ASN1_GENERALIZED_TIME 0x18
#define MBEDTLS_ASN1_UNIVERSAL_STRING 0x1C
#define MBEDTLS_ASN1_BMP_STRING 0x1E
#define MBEDTLS_ASN1_PRIMITIVE 0x00
#define MBEDTLS_ASN1_CONSTRUCTED 0x20
#define MBEDTLS_ASN1_CONTEXT_SPECIFIC 0x80
/*
* Bit masks for each of the components of an ASN.1 tag as specified in
* ITU X.690 (08/2015), section 8.1 "General rules for encoding",
* paragraph 8.1.2.2:
*
* Bit 8 7 6 5 1
* +-------+-----+------------+
* | Class | P/C | Tag number |
* +-------+-----+------------+
*/
#define MBEDTLS_ASN1_TAG_CLASS_MASK 0xC0
#define MBEDTLS_ASN1_TAG_PC_MASK 0x20
#define MBEDTLS_ASN1_TAG_VALUE_MASK 0x1F
/* \} name */
/* \} addtogroup asn1_module */
/** Returns the size of the binary string, without the trailing \\0 */
#define MBEDTLS_OID_SIZE(x) (sizeof(x) - 1)
/**
* Compares an mbedtls_asn1_buf structure to a reference OID.
*
* Only works for 'defined' oid_str values (MBEDTLS_OID_HMAC_SHA1), you cannot use a
* 'unsigned char *oid' here!
*/
#define MBEDTLS_OID_CMP(oid_str, oid_buf) \
( ( MBEDTLS_OID_SIZE(oid_str) != (oid_buf)->len ) || \
memcmp( (oid_str), (oid_buf)->p, (oid_buf)->len) != 0 )
#ifdef __cplusplus
extern "C" {
#endif
/**
* \name Functions to parse ASN.1 data structures
* \{
*/
/**
* Type-length-value structure that allows for ASN1 using DER.
*/
typedef struct mbedtls_asn1_buf
{
int tag; /**< ASN1 type, e.g. MBEDTLS_ASN1_UTF8_STRING. */
size_t len; /**< ASN1 length, in octets. */
unsigned char *p; /**< ASN1 data, e.g. in ASCII. */
}
mbedtls_asn1_buf;
/**
* Container for ASN1 bit strings.
*/
typedef struct mbedtls_asn1_bitstring
{
size_t len; /**< ASN1 length, in octets. */
unsigned char unused_bits; /**< Number of unused bits at the end of the string */
unsigned char *p; /**< Raw ASN1 data for the bit string */
}
mbedtls_asn1_bitstring;
/**
* Container for a sequence of ASN.1 items
*/
typedef struct mbedtls_asn1_sequence
{
mbedtls_asn1_buf buf; /**< Buffer containing the given ASN.1 item. */
struct mbedtls_asn1_sequence *next; /**< The next entry in the sequence. */
}
mbedtls_asn1_sequence;
/**
* Container for a sequence or list of 'named' ASN.1 data items
*/
typedef struct mbedtls_asn1_named_data
{
mbedtls_asn1_buf oid; /**< The object identifier. */
mbedtls_asn1_buf val; /**< The named value. */
struct mbedtls_asn1_named_data *next; /**< The next entry in the sequence. */
unsigned char next_merged; /**< Merge next item into the current one? */
}
mbedtls_asn1_named_data;
/**
* \brief Get the length of an ASN.1 element.
* Updates the pointer to immediately behind the length.
*
* \param p On entry, \c *p points to the first byte of the length,
* i.e. immediately after the tag.
* On successful completion, \c *p points to the first byte
* after the length, i.e. the first byte of the content.
* On error, the value of \c *p is undefined.
* \param end End of data.
* \param len On successful completion, \c *len contains the lengtth
* read from the ASN.1 input.
*
* \return 0 if successful.
* \return #MBEDTLS_ERR_ASN1_OUT_OF_DATA if the ASN.1 element
* would end beyond \p end.
* \return #MBEDTLS_ERR_ASN1_INVALID_LENGTH if the length is unparseable.
*/
int mbedtls_asn1_get_len( unsigned char **p,
const unsigned char *end,
size_t *len );
/**
* \brief Get the tag and length of the element.
* Check for the requested tag.
* Updates the pointer to immediately behind the tag and length.
*
* \param p On entry, \c *p points to the start of the ASN.1 element.
* On successful completion, \c *p points to the first byte
* after the length, i.e. the first byte of the content.
* On error, the value of \c *p is undefined.
* \param end End of data.
* \param len On successful completion, \c *len contains the lengtth
* read from the ASN.1 input.
* \param tag The expected tag.
*
* \return 0 if successful.
* \return #MBEDTLS_ERR_ASN1_UNEXPECTED_TAG if the data does not start
* with the requested tag.
* \return #MBEDTLS_ERR_ASN1_OUT_OF_DATA if the ASN.1 element
* would end beyond \p end.
* \return #MBEDTLS_ERR_ASN1_INVALID_LENGTH if the length is unparseable.
*/
int mbedtls_asn1_get_tag( unsigned char **p,
const unsigned char *end,
size_t *len, int tag );
/**
* \brief Retrieve a boolean ASN.1 tag and its value.
* Updates the pointer to immediately behind the full tag.
*
* \param p On entry, \c *p points to the start of the ASN.1 element.
* On successful completion, \c *p points to the first byte
* beyond the ASN.1 element.
* On error, the value of \c *p is undefined.
* \param end End of data.
* \param val On success, the parsed value (\c 0 or \c 1).
*
* \return 0 if successful.
* \return An ASN.1 error code if the input does not start with
* a valid ASN.1 BOOLEAN.
*/
int mbedtls_asn1_get_bool( unsigned char **p,
const unsigned char *end,
int *val );
/**
* \brief Retrieve an integer ASN.1 tag and its value.
* Updates the pointer to immediately behind the full tag.
*
* \param p On entry, \c *p points to the start of the ASN.1 element.
* On successful completion, \c *p points to the first byte
* beyond the ASN.1 element.
* On error, the value of \c *p is undefined.
* \param end End of data.
* \param val On success, the parsed value.
*
* \return 0 if successful.
* \return An ASN.1 error code if the input does not start with
* a valid ASN.1 INTEGER.
* \return #MBEDTLS_ERR_ASN1_INVALID_LENGTH if the parsed value does
* not fit in an \c int.
* \return An ASN.1 error code if the input does not start with
* a valid ASN.1 INTEGER.
*/
int mbedtls_asn1_get_int( unsigned char **p,
const unsigned char *end,
int *val );
/**
* \brief Retrieve a bitstring ASN.1 tag and its value.
* Updates the pointer to immediately behind the full tag.
*
* \param p On entry, \c *p points to the start of the ASN.1 element.
* On successful completion, \c *p is equal to \p end.
* On error, the value of \c *p is undefined.
* \param end End of data.
* \param bs On success, ::mbedtls_asn1_bitstring information about
* the parsed value.
*
* \return 0 if successful.
* \return #MBEDTLS_ERR_ASN1_LENGTH_MISMATCH if the input contains
* extra data after a valid BIT STRING.
* \return An ASN.1 error code if the input does not start with
* a valid ASN.1 BIT STRING.
*/
int mbedtls_asn1_get_bitstring( unsigned char **p, const unsigned char *end,
mbedtls_asn1_bitstring *bs );
/**
* \brief Retrieve a bitstring ASN.1 tag without unused bits and its
* value.
* Updates the pointer to the beginning of the bit/octet string.
*
* \param p On entry, \c *p points to the start of the ASN.1 element.
* On successful completion, \c *p points to the first byte
* of the content of the BIT STRING.
* On error, the value of \c *p is undefined.
* \param end End of data.
* \param len On success, \c *len is the length of the content in bytes.
*
* \return 0 if successful.
* \return #MBEDTLS_ERR_ASN1_INVALID_DATA if the input starts with
* a valid BIT STRING with a nonzero number of unused bits.
* \return An ASN.1 error code if the input does not start with
* a valid ASN.1 BIT STRING.
*/
int mbedtls_asn1_get_bitstring_null( unsigned char **p,
const unsigned char *end,
size_t *len );
/**
* \brief Parses and splits an ASN.1 "SEQUENCE OF <tag>"
* Updated the pointer to immediately behind the full sequence tag.
*
* \note On error, this function may return a partial list in \p cur.
* You must set `cur->next = NULL` before calling this function!
* Otherwise it is impossible to distinguish a previously non-null
* pointer from a pointer to an object allocated by this function.
*
* \note If the sequence is empty, this function does not modify
* \c *cur. If the sequence is valid and non-empty, this
* function sets `cur->buf.tag` to \p tag. This allows
* callers to distinguish between an empty sequence and
* a one-element sequence.
*
* \param p On entry, \c *p points to the start of the ASN.1 element.
* On successful completion, \c *p is equal to \p end.
* On error, the value of \c *p is undefined.
* \param end End of data.
* \param cur A ::mbedtls_asn1_sequence which this function fills.
* When this function returns, \c *cur is the head of a linked
* list. Each node in this list is allocated with
* mbedtls_calloc() apart from \p cur itself, and should
* therefore be freed with mbedtls_free().
* The list describes the content of the sequence.
* The head of the list (i.e. \c *cur itself) describes the
* first element, `*cur->next` describes the second element, etc.
* For each element, `buf.tag == tag`, `buf.len` is the length
* of the content of the content of the element, and `buf.p`
* points to the first byte of the content (i.e. immediately
* past the length of the element).
* Note that list elements may be allocated even on error.
* \param tag Each element of the sequence must have this tag.
*
* \return 0 if successful.
* \return #MBEDTLS_ERR_ASN1_LENGTH_MISMATCH if the input contains
* extra data after a valid SEQUENCE OF \p tag.
* \return #MBEDTLS_ERR_ASN1_ALLOC_FAILED if a memory allocation failed.
* \return An ASN.1 error code if the input does not start with
* a valid ASN.1 BIT STRING.
*/
int mbedtls_asn1_get_sequence_of( unsigned char **p,
const unsigned char *end,
mbedtls_asn1_sequence *cur,
int tag );
#if defined(MBEDTLS_BIGNUM_C)
/**
* \brief Retrieve an integer ASN.1 tag and its value.
* Updates the pointer to immediately behind the full tag.
*
* \param p On entry, \c *p points to the start of the ASN.1 element.
* On successful completion, \c *p points to the first byte
* beyond the ASN.1 element.
* On error, the value of \c *p is undefined.
* \param end End of data.
* \param X On success, the parsed value.
*
* \return 0 if successful.
* \return An ASN.1 error code if the input does not start with
* a valid ASN.1 INTEGER.
* \return #MBEDTLS_ERR_ASN1_INVALID_LENGTH if the parsed value does
* not fit in an \c int.
* \return An MPI error code if the parsed value is too large.
* \return An ASN.1 error code if the input does not start with
* a valid ASN.1 INTEGER.
*/
int mbedtls_asn1_get_mpi( unsigned char **p,
const unsigned char *end,
mbedtls_mpi *X );
#endif /* MBEDTLS_BIGNUM_C */
/**
* \brief Retrieve an AlgorithmIdentifier ASN.1 sequence.
* Updates the pointer to immediately behind the full
* AlgorithmIdentifier.
*
* \param p On entry, \c *p points to the start of the ASN.1 element.
* On successful completion, \c *p points to the first byte
* beyond the AlgorithmIdentifier element.
* On error, the value of \c *p is undefined.
* \param end End of data.
* \param alg The buffer to receive the OID.
* \param params The buffer to receive the parameters.
* This is zeroized if there are no parameters.
*
* \return 0 if successful or a specific ASN.1 or MPI error code.
*/
int mbedtls_asn1_get_alg( unsigned char **p,
const unsigned char *end,
mbedtls_asn1_buf *alg, mbedtls_asn1_buf *params );
/**
* \brief Retrieve an AlgorithmIdentifier ASN.1 sequence with NULL or no
* params.
* Updates the pointer to immediately behind the full
* AlgorithmIdentifier.
*
* \param p On entry, \c *p points to the start of the ASN.1 element.
* On successful completion, \c *p points to the first byte
* beyond the AlgorithmIdentifier element.
* On error, the value of \c *p is undefined.
* \param end End of data.
* \param alg The buffer to receive the OID.
*
* \return 0 if successful or a specific ASN.1 or MPI error code.
*/
int mbedtls_asn1_get_alg_null( unsigned char **p,
const unsigned char *end,
mbedtls_asn1_buf *alg );
/**
* \brief Find a specific named_data entry in a sequence or list based on
* the OID.
*
* \param list The list to seek through
* \param oid The OID to look for
* \param len Size of the OID
*
* \return NULL if not found, or a pointer to the existing entry.
*/
mbedtls_asn1_named_data *mbedtls_asn1_find_named_data( mbedtls_asn1_named_data *list,
const char *oid, size_t len );
/**
* \brief Free a mbedtls_asn1_named_data entry
*
* \param entry The named data entry to free.
* This function calls mbedtls_free() on
* `entry->oid.p` and `entry->val.p`.
*/
void mbedtls_asn1_free_named_data( mbedtls_asn1_named_data *entry );
/**
* \brief Free all entries in a mbedtls_asn1_named_data list.
*
* \param head Pointer to the head of the list of named data entries to free.
* This function calls mbedtls_asn1_free_named_data() and
* mbedtls_free() on each list element and
* sets \c *head to \c NULL.
*/
void mbedtls_asn1_free_named_data_list( mbedtls_asn1_named_data **head );
#ifdef __cplusplus
}
#endif
#endif /* asn1.h */