Merge pull request #7106 from davidhorstmann-arm/parse-oid-from-string
Parse an OID from a string
This commit is contained in:
commit
d598eaf212
5 changed files with 277 additions and 0 deletions
3
ChangeLog.d/oid-parse-from-numeric-string.txt
Normal file
3
ChangeLog.d/oid-parse-from-numeric-string.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
Features
|
||||||
|
* Add function mbedtls_oid_from_numeric_string() to parse an OID from a
|
||||||
|
string to a DER-encoded mbedtls_asn1_buf.
|
|
@ -63,6 +63,11 @@
|
||||||
#define MBEDTLS_OID_X509_EXT_FRESHEST_CRL (1 << 14)
|
#define MBEDTLS_OID_X509_EXT_FRESHEST_CRL (1 << 14)
|
||||||
#define MBEDTLS_OID_X509_EXT_NS_CERT_TYPE (1 << 16)
|
#define MBEDTLS_OID_X509_EXT_NS_CERT_TYPE (1 << 16)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maximum number of OID components allowed
|
||||||
|
*/
|
||||||
|
#define MBEDTLS_OID_MAX_COMPONENTS 128
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Top level OID tuples
|
* Top level OID tuples
|
||||||
*/
|
*/
|
||||||
|
@ -478,6 +483,25 @@ typedef struct mbedtls_oid_descriptor_t {
|
||||||
*/
|
*/
|
||||||
int mbedtls_oid_get_numeric_string(char *buf, size_t size, const mbedtls_asn1_buf *oid);
|
int mbedtls_oid_get_numeric_string(char *buf, size_t size, const mbedtls_asn1_buf *oid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Translate a string containing a dotted-decimal
|
||||||
|
* representation of an ASN.1 OID into its encoded form
|
||||||
|
* (e.g. "1.2.840.113549" into "\x2A\x86\x48\x86\xF7\x0D").
|
||||||
|
* On success, this function allocates oid->buf from the
|
||||||
|
* heap. It must be freed by the caller using mbedtls_free().
|
||||||
|
*
|
||||||
|
* \param oid #mbedtls_asn1_buf to populate with the DER-encoded OID
|
||||||
|
* \param oid_str string representation of the OID to parse
|
||||||
|
* \param size length of the OID string, not including any null terminator
|
||||||
|
*
|
||||||
|
* \return 0 if successful
|
||||||
|
* \return #MBEDTLS_ERR_ASN1_INVALID_DATA if \p oid_str does not
|
||||||
|
* represent a valid OID
|
||||||
|
* \return #MBEDTLS_ERR_ASN1_ALLOC_FAILED if the function fails to
|
||||||
|
* allocate oid->buf
|
||||||
|
*/
|
||||||
|
int mbedtls_oid_from_numeric_string(mbedtls_asn1_buf *oid, const char *oid_str, size_t size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Translate an X.509 extension OID into local values
|
* \brief Translate an X.509 extension OID into local values
|
||||||
*
|
*
|
||||||
|
|
176
library/oid.c
176
library/oid.c
|
@ -933,4 +933,180 @@ int mbedtls_oid_get_numeric_string(char *buf, size_t size,
|
||||||
return (int) (size - n);
|
return (int) (size - n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int oid_parse_number(unsigned int *num, const char **p, const char *bound)
|
||||||
|
{
|
||||||
|
int ret = MBEDTLS_ERR_ASN1_INVALID_DATA;
|
||||||
|
|
||||||
|
*num = 0;
|
||||||
|
|
||||||
|
while (*p < bound && **p >= '0' && **p <= '9') {
|
||||||
|
ret = 0;
|
||||||
|
if (*num > (UINT_MAX / 10)) {
|
||||||
|
return MBEDTLS_ERR_ASN1_INVALID_DATA;
|
||||||
|
}
|
||||||
|
*num *= 10;
|
||||||
|
*num += **p - '0';
|
||||||
|
(*p)++;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t oid_subidentifier_num_bytes(unsigned int value)
|
||||||
|
{
|
||||||
|
size_t num_bytes = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
value >>= 7;
|
||||||
|
num_bytes++;
|
||||||
|
} while (value != 0);
|
||||||
|
|
||||||
|
return num_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int oid_subidentifier_encode_into(unsigned char **p,
|
||||||
|
unsigned char *bound,
|
||||||
|
unsigned int value)
|
||||||
|
{
|
||||||
|
size_t num_bytes = oid_subidentifier_num_bytes(value);
|
||||||
|
|
||||||
|
if ((size_t) (bound - *p) < num_bytes) {
|
||||||
|
return MBEDTLS_ERR_OID_BUF_TOO_SMALL;
|
||||||
|
}
|
||||||
|
(*p)[num_bytes - 1] = (unsigned char) (value & 0x7f);
|
||||||
|
value >>= 7;
|
||||||
|
|
||||||
|
for (size_t i = 2; i <= num_bytes; i++) {
|
||||||
|
(*p)[num_bytes - i] = 0x80 | (unsigned char) (value & 0x7f);
|
||||||
|
value >>= 7;
|
||||||
|
}
|
||||||
|
*p += num_bytes;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the OID for the given x.y.z.... style numeric string */
|
||||||
|
int mbedtls_oid_from_numeric_string(mbedtls_asn1_buf *oid,
|
||||||
|
const char *oid_str, size_t size)
|
||||||
|
{
|
||||||
|
int ret = MBEDTLS_ERR_ASN1_INVALID_DATA;
|
||||||
|
const char *str_ptr = oid_str;
|
||||||
|
const char *str_bound = oid_str + size;
|
||||||
|
unsigned int val = 0;
|
||||||
|
unsigned int component1, component2;
|
||||||
|
size_t encoded_len;
|
||||||
|
unsigned char *resized_mem;
|
||||||
|
|
||||||
|
/* Count the number of dots to get a worst-case allocation size. */
|
||||||
|
size_t num_dots = 0;
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
if (oid_str[i] == '.') {
|
||||||
|
num_dots++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Allocate maximum possible required memory:
|
||||||
|
* There are (num_dots + 1) integer components, but the first 2 share the
|
||||||
|
* same subidentifier, so we only need num_dots subidentifiers maximum. */
|
||||||
|
if (num_dots == 0 || (num_dots > MBEDTLS_OID_MAX_COMPONENTS - 1)) {
|
||||||
|
return MBEDTLS_ERR_ASN1_INVALID_DATA;
|
||||||
|
}
|
||||||
|
/* Each byte can store 7 bits, calculate number of bytes for a
|
||||||
|
* subidentifier:
|
||||||
|
*
|
||||||
|
* bytes = ceil(subidentifer_size * 8 / 7)
|
||||||
|
*/
|
||||||
|
size_t bytes_per_subidentifier = (((sizeof(unsigned int) * 8) - 1) / 7)
|
||||||
|
+ 1;
|
||||||
|
size_t max_possible_bytes = num_dots * bytes_per_subidentifier;
|
||||||
|
oid->p = mbedtls_calloc(max_possible_bytes, 1);
|
||||||
|
if (oid->p == NULL) {
|
||||||
|
return MBEDTLS_ERR_ASN1_ALLOC_FAILED;
|
||||||
|
}
|
||||||
|
unsigned char *out_ptr = oid->p;
|
||||||
|
unsigned char *out_bound = oid->p + max_possible_bytes;
|
||||||
|
|
||||||
|
ret = oid_parse_number(&component1, &str_ptr, str_bound);
|
||||||
|
if (ret != 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (component1 > 2) {
|
||||||
|
/* First component can't be > 2 */
|
||||||
|
ret = MBEDTLS_ERR_ASN1_INVALID_DATA;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (str_ptr >= str_bound || *str_ptr != '.') {
|
||||||
|
ret = MBEDTLS_ERR_ASN1_INVALID_DATA;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
str_ptr++;
|
||||||
|
|
||||||
|
ret = oid_parse_number(&component2, &str_ptr, str_bound);
|
||||||
|
if (ret != 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if ((component1 < 2) && (component2 > 39)) {
|
||||||
|
/* Root nodes 0 and 1 may have up to 40 children, numbered 0-39 */
|
||||||
|
ret = MBEDTLS_ERR_ASN1_INVALID_DATA;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (str_ptr < str_bound) {
|
||||||
|
if (*str_ptr == '.') {
|
||||||
|
str_ptr++;
|
||||||
|
} else {
|
||||||
|
ret = MBEDTLS_ERR_ASN1_INVALID_DATA;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (component2 > (UINT_MAX - (component1 * 40))) {
|
||||||
|
ret = MBEDTLS_ERR_ASN1_INVALID_DATA;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
ret = oid_subidentifier_encode_into(&out_ptr, out_bound,
|
||||||
|
(component1 * 40) + component2);
|
||||||
|
if (ret != 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (str_ptr < str_bound) {
|
||||||
|
ret = oid_parse_number(&val, &str_ptr, str_bound);
|
||||||
|
if (ret != 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (str_ptr < str_bound) {
|
||||||
|
if (*str_ptr == '.') {
|
||||||
|
str_ptr++;
|
||||||
|
} else {
|
||||||
|
ret = MBEDTLS_ERR_ASN1_INVALID_DATA;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = oid_subidentifier_encode_into(&out_ptr, out_bound, val);
|
||||||
|
if (ret != 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encoded_len = out_ptr - oid->p;
|
||||||
|
resized_mem = mbedtls_calloc(encoded_len, 1);
|
||||||
|
if (resized_mem == NULL) {
|
||||||
|
ret = MBEDTLS_ERR_ASN1_ALLOC_FAILED;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
memcpy(resized_mem, oid->p, encoded_len);
|
||||||
|
mbedtls_free(oid->p);
|
||||||
|
oid->p = resized_mem;
|
||||||
|
oid->len = encoded_len;
|
||||||
|
|
||||||
|
oid->tag = MBEDTLS_ASN1_OID;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
mbedtls_free(oid->p);
|
||||||
|
oid->p = NULL;
|
||||||
|
oid->len = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* MBEDTLS_OID_C */
|
#endif /* MBEDTLS_OID_C */
|
||||||
|
|
|
@ -137,3 +137,51 @@ oid_get_numeric_string:"8001":MBEDTLS_ERR_ASN1_INVALID_DATA:""
|
||||||
|
|
||||||
OID get numeric string - overlong encoding, second subidentifier
|
OID get numeric string - overlong encoding, second subidentifier
|
||||||
oid_get_numeric_string:"2B8001":MBEDTLS_ERR_ASN1_INVALID_DATA:""
|
oid_get_numeric_string:"2B8001":MBEDTLS_ERR_ASN1_INVALID_DATA:""
|
||||||
|
|
||||||
|
OID from numeric string - hardware module name
|
||||||
|
oid_from_numeric_string:"1.3.6.1.5.5.7.8.4":0:"2B06010505070804"
|
||||||
|
|
||||||
|
OID from numeric string - multi-byte subidentifier
|
||||||
|
oid_from_numeric_string:"1.1.2108":0:"29903C"
|
||||||
|
|
||||||
|
OID from numeric string - second component greater than 39
|
||||||
|
oid_from_numeric_string:"2.49.0.0.826.0":0:"81010000863A00"
|
||||||
|
|
||||||
|
OID from numeric string - multi-byte first subidentifier
|
||||||
|
oid_from_numeric_string:"2.999":0:"8837"
|
||||||
|
|
||||||
|
OID from numeric string - empty string input
|
||||||
|
oid_from_numeric_string:"":MBEDTLS_ERR_ASN1_INVALID_DATA:""
|
||||||
|
|
||||||
|
OID from numeric string - first component not a number
|
||||||
|
oid_from_numeric_string:"abc.1.2":MBEDTLS_ERR_ASN1_INVALID_DATA:""
|
||||||
|
|
||||||
|
OID from numeric string - second component not a number
|
||||||
|
oid_from_numeric_string:"1.abc.2":MBEDTLS_ERR_ASN1_INVALID_DATA:""
|
||||||
|
|
||||||
|
OID from numeric string - first component too large
|
||||||
|
oid_from_numeric_string:"3.1":MBEDTLS_ERR_ASN1_INVALID_DATA:""
|
||||||
|
|
||||||
|
OID from numeric string - first component < 2, second > 39
|
||||||
|
oid_from_numeric_string:"1.40":MBEDTLS_ERR_ASN1_INVALID_DATA:""
|
||||||
|
|
||||||
|
OID from numeric string - third component not a number
|
||||||
|
oid_from_numeric_string:"1.2.abc":MBEDTLS_ERR_ASN1_INVALID_DATA:""
|
||||||
|
|
||||||
|
OID from numeric string - non-'.' separator between first and second
|
||||||
|
oid_from_numeric_string:"1/2.3.4":MBEDTLS_ERR_ASN1_INVALID_DATA:""
|
||||||
|
|
||||||
|
OID from numeric string - non-'.' separator between second and third
|
||||||
|
oid_from_numeric_string:"1.2/3.4":MBEDTLS_ERR_ASN1_INVALID_DATA:""
|
||||||
|
|
||||||
|
OID from numeric string - non-'.' separator between third and fourth
|
||||||
|
oid_from_numeric_string:"1.2.3/4":MBEDTLS_ERR_ASN1_INVALID_DATA:""
|
||||||
|
|
||||||
|
OID from numeric string - OID greater than max length (129 components)
|
||||||
|
oid_from_numeric_string:"1.2.3.4.5.6.7.8.1.2.3.4.5.6.7.8.1.2.3.4.5.6.7.8.1.2.3.4.5.6.7.8.1.2.3.4.5.6.7.8.1.2.3.4.5.6.7.8.1.2.3.4.5.6.7.8.1.2.3.4.5.6.7.8.1.2.3.4.5.6.7.8.1.2.3.4.5.6.7.8.1.2.3.4.5.6.7.8.1.2.3.4.5.6.7.8.1.2.3.4.5.6.7.8.1.2.3.4.5.6.7.8.1.2.3.4.5.6.7.8.1.2.3.4.5.6.7.8.1":MBEDTLS_ERR_ASN1_INVALID_DATA:""
|
||||||
|
|
||||||
|
OID from numeric string - OID with maximum subidentifier
|
||||||
|
oid_from_numeric_string:"2.4294967215":0:"8FFFFFFF7F"
|
||||||
|
|
||||||
|
OID from numeric string - OID with overflowing subidentifier
|
||||||
|
oid_from_numeric_string:"2.4294967216":MBEDTLS_ERR_ASN1_INVALID_DATA:""
|
||||||
|
|
|
@ -119,3 +119,29 @@ void oid_get_numeric_string(data_t *oid, int error_ret, char *result_str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* END_CASE */
|
/* END_CASE */
|
||||||
|
|
||||||
|
/* BEGIN_CASE */
|
||||||
|
void oid_from_numeric_string(char *oid_str, int error_ret,
|
||||||
|
data_t *exp_oid_buf)
|
||||||
|
{
|
||||||
|
mbedtls_asn1_buf oid = { 0, 0, NULL };
|
||||||
|
mbedtls_asn1_buf exp_oid = { 0, 0, NULL };
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
exp_oid.tag = MBEDTLS_ASN1_OID;
|
||||||
|
exp_oid.p = exp_oid_buf->x;
|
||||||
|
exp_oid.len = exp_oid_buf->len;
|
||||||
|
|
||||||
|
ret = mbedtls_oid_from_numeric_string(&oid, oid_str, strlen(oid_str));
|
||||||
|
|
||||||
|
if (error_ret == 0) {
|
||||||
|
TEST_EQUAL(oid.len, exp_oid.len);
|
||||||
|
TEST_ASSERT(memcmp(oid.p, exp_oid.p, oid.len) == 0);
|
||||||
|
mbedtls_free(oid.p);
|
||||||
|
oid.p = NULL;
|
||||||
|
oid.len = 0;
|
||||||
|
} else {
|
||||||
|
TEST_EQUAL(ret, error_ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* END_CASE */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue