mirror of
https://github.com/Mbed-TLS/mbedtls.git
synced 2025-08-01 10:06:53 +03:00
Merge pull request #8025 from AgathiyanB/accept-numericoid-hexstring-x509
Accept numericoid hexstring x509
This commit is contained in:
@ -19,7 +19,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#if defined(MBEDTLS_ASN1_PARSE_C)
|
||||
#if defined(MBEDTLS_ASN1_PARSE_C) || defined(MBEDTLS_X509_CREATE_C)
|
||||
|
||||
#include "mbedtls/asn1.h"
|
||||
#include "mbedtls/platform_util.h"
|
||||
@ -114,7 +114,9 @@ int mbedtls_asn1_get_tag(unsigned char **p,
|
||||
|
||||
return mbedtls_asn1_get_len(p, end, len);
|
||||
}
|
||||
#endif /* MBEDTLS_ASN1_PARSE_C || MBEDTLS_X509_CREATE_C */
|
||||
|
||||
#if defined(MBEDTLS_ASN1_PARSE_C)
|
||||
int mbedtls_asn1_get_bool(unsigned char **p,
|
||||
const unsigned char *end,
|
||||
int *val)
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#if defined(MBEDTLS_ASN1_WRITE_C)
|
||||
#if defined(MBEDTLS_ASN1_WRITE_C) || defined(MBEDTLS_X509_USE_C)
|
||||
|
||||
#include "mbedtls/asn1write.h"
|
||||
#include "mbedtls/error.h"
|
||||
@ -102,7 +102,9 @@ int mbedtls_asn1_write_tag(unsigned char **p, const unsigned char *start, unsign
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* MBEDTLS_ASN1_WRITE_C || MBEDTLS_X509_USE_C */
|
||||
|
||||
#if defined(MBEDTLS_ASN1_WRITE_C)
|
||||
int mbedtls_asn1_write_raw_buffer(unsigned char **p, const unsigned char *start,
|
||||
const unsigned char *buf, size_t size)
|
||||
{
|
||||
|
103
library/x509.c
103
library/x509.c
@ -43,6 +43,8 @@
|
||||
#include "mbedtls/pem.h"
|
||||
#endif
|
||||
|
||||
#include "mbedtls/asn1write.h"
|
||||
|
||||
#include "mbedtls/platform.h"
|
||||
|
||||
#if defined(MBEDTLS_HAVE_TIME)
|
||||
@ -810,6 +812,11 @@ int mbedtls_x509_get_ext(unsigned char **p, const unsigned char *end,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char nibble_to_hex_digit(int i)
|
||||
{
|
||||
return (i < 10) ? (i + '0') : (i - 10 + 'A');
|
||||
}
|
||||
|
||||
/*
|
||||
* Store the name in printable form into buf; no more
|
||||
* than size characters will be written
|
||||
@ -817,11 +824,16 @@ int mbedtls_x509_get_ext(unsigned char **p, const unsigned char *end,
|
||||
int mbedtls_x509_dn_gets(char *buf, size_t size, const mbedtls_x509_name *dn)
|
||||
{
|
||||
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
||||
size_t i, j, n;
|
||||
size_t i, j, n, asn1_len_size, asn1_tag_size, asn1_tag_len_buf_start;
|
||||
/* 6 is enough as our asn1 write functions only write one byte for the tag and at most five bytes for the length*/
|
||||
unsigned char asn1_tag_len_buf[6];
|
||||
unsigned char *asn1_len_p;
|
||||
unsigned char c, merge = 0;
|
||||
const mbedtls_x509_name *name;
|
||||
const char *short_name = NULL;
|
||||
char lowbits, highbits;
|
||||
char s[MBEDTLS_X509_MAX_DN_NAME_SIZE], *p;
|
||||
int print_hexstring;
|
||||
|
||||
memset(s, 0, sizeof(s));
|
||||
|
||||
@ -840,32 +852,91 @@ int mbedtls_x509_dn_gets(char *buf, size_t size, const mbedtls_x509_name *dn)
|
||||
MBEDTLS_X509_SAFE_SNPRINTF;
|
||||
}
|
||||
|
||||
ret = mbedtls_oid_get_attr_short_name(&name->oid, &short_name);
|
||||
print_hexstring = (name->val.tag != MBEDTLS_ASN1_UTF8_STRING) &&
|
||||
(name->val.tag != MBEDTLS_ASN1_PRINTABLE_STRING) &&
|
||||
(name->val.tag != MBEDTLS_ASN1_IA5_STRING);
|
||||
|
||||
if (ret == 0) {
|
||||
if ((ret = mbedtls_oid_get_attr_short_name(&name->oid, &short_name)) == 0) {
|
||||
ret = mbedtls_snprintf(p, n, "%s=", short_name);
|
||||
} else {
|
||||
ret = mbedtls_snprintf(p, n, "\?\?=");
|
||||
if ((ret = mbedtls_oid_get_numeric_string(p, n, &name->oid)) > 0) {
|
||||
n -= ret;
|
||||
p += ret;
|
||||
ret = mbedtls_snprintf(p, n, "=");
|
||||
print_hexstring = 1;
|
||||
} else if (ret == MBEDTLS_ERR_OID_BUF_TOO_SMALL) {
|
||||
return MBEDTLS_ERR_X509_BUFFER_TOO_SMALL;
|
||||
} else {
|
||||
ret = mbedtls_snprintf(p, n, "\?\?=");
|
||||
}
|
||||
}
|
||||
MBEDTLS_X509_SAFE_SNPRINTF;
|
||||
|
||||
for (i = 0, j = 0; i < name->val.len; i++, j++) {
|
||||
if (j >= sizeof(s) - 1) {
|
||||
return MBEDTLS_ERR_X509_BUFFER_TOO_SMALL;
|
||||
}
|
||||
if (print_hexstring) {
|
||||
s[0] = '#';
|
||||
|
||||
c = name->val.p[i];
|
||||
// Special characters requiring escaping, RFC 1779
|
||||
if (c && strchr(",=+<>#;\"\\", c)) {
|
||||
asn1_len_p = asn1_tag_len_buf + sizeof(asn1_tag_len_buf);
|
||||
if ((ret = mbedtls_asn1_write_len(&asn1_len_p, asn1_tag_len_buf, name->val.len)) < 0) {
|
||||
return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
||||
}
|
||||
asn1_len_size = ret;
|
||||
if ((ret = mbedtls_asn1_write_tag(&asn1_len_p, asn1_tag_len_buf, name->val.tag)) < 0) {
|
||||
return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
||||
}
|
||||
asn1_tag_size = ret;
|
||||
asn1_tag_len_buf_start = sizeof(asn1_tag_len_buf) - asn1_len_size - asn1_tag_size;
|
||||
for (i = 0, j = 1; i < asn1_len_size + asn1_tag_size; i++) {
|
||||
if (j + 1 >= sizeof(s) - 1) {
|
||||
return MBEDTLS_ERR_X509_BUFFER_TOO_SMALL;
|
||||
}
|
||||
s[j++] = '\\';
|
||||
c = asn1_tag_len_buf[asn1_tag_len_buf_start+i];
|
||||
lowbits = (c & 0x0F);
|
||||
highbits = c >> 4;
|
||||
s[j++] = nibble_to_hex_digit(highbits);
|
||||
s[j++] = nibble_to_hex_digit(lowbits);
|
||||
}
|
||||
if (c < 32 || c >= 127) {
|
||||
s[j] = '?';
|
||||
} else {
|
||||
s[j] = c;
|
||||
for (i = 0; i < name->val.len; i++) {
|
||||
if (j + 1 >= sizeof(s) - 1) {
|
||||
return MBEDTLS_ERR_X509_BUFFER_TOO_SMALL;
|
||||
}
|
||||
c = name->val.p[i];
|
||||
lowbits = (c & 0x0F);
|
||||
highbits = c >> 4;
|
||||
s[j++] = nibble_to_hex_digit(highbits);
|
||||
s[j++] = nibble_to_hex_digit(lowbits);
|
||||
}
|
||||
} else {
|
||||
for (i = 0, j = 0; i < name->val.len; i++, j++) {
|
||||
if (j >= sizeof(s) - 1) {
|
||||
return MBEDTLS_ERR_X509_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
c = name->val.p[i];
|
||||
// Special characters requiring escaping, RFC 4514 Section 2.4
|
||||
if (c == '\0') {
|
||||
return MBEDTLS_ERR_X509_INVALID_NAME;
|
||||
} else {
|
||||
if (strchr(",=+<>;\"\\", c) ||
|
||||
((i == 0) && strchr("# ", c)) ||
|
||||
((i == name->val.len-1) && (c == ' '))) {
|
||||
if (j + 1 >= sizeof(s) - 1) {
|
||||
return MBEDTLS_ERR_X509_BUFFER_TOO_SMALL;
|
||||
}
|
||||
s[j++] = '\\';
|
||||
}
|
||||
}
|
||||
if (c < 32 || c >= 127) {
|
||||
if (j + 3 >= sizeof(s) - 1) {
|
||||
return MBEDTLS_ERR_X509_BUFFER_TOO_SMALL;
|
||||
}
|
||||
s[j++] = '\\';
|
||||
lowbits = (c & 0x0F);
|
||||
highbits = c >> 4;
|
||||
s[j++] = nibble_to_hex_digit(highbits);
|
||||
s[j] = nibble_to_hex_digit(lowbits);
|
||||
} else {
|
||||
s[j] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
s[j] = '\0';
|
||||
|
@ -28,6 +28,10 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "mbedtls/platform.h"
|
||||
|
||||
#include "mbedtls/asn1.h"
|
||||
|
||||
/* Structure linking OIDs for X.509 DN AttributeTypes to their
|
||||
* string representations and default string encodings used by Mbed TLS. */
|
||||
typedef struct {
|
||||
@ -35,7 +39,8 @@ typedef struct {
|
||||
* "CN" or "emailAddress". */
|
||||
size_t name_len; /* Length of 'name', without trailing 0 byte. */
|
||||
const char *oid; /* String representation of OID of AttributeType,
|
||||
* as per RFC 5280, Appendix A.1. */
|
||||
* as per RFC 5280, Appendix A.1. encoded as per
|
||||
* X.690 */
|
||||
int default_tag; /* The default character encoding used for the
|
||||
* given attribute type, e.g.
|
||||
* MBEDTLS_ASN1_UTF8_STRING for UTF-8. */
|
||||
@ -123,79 +128,200 @@ static const x509_attr_descriptor_t *x509_attr_descr_from_name(const char *name,
|
||||
return cur;
|
||||
}
|
||||
|
||||
static int hex_to_int(char c)
|
||||
{
|
||||
return ('0' <= c && c <= '9') ? (c - '0') :
|
||||
('a' <= c && c <= 'f') ? (c - 'a' + 10) :
|
||||
('A' <= c && c <= 'F') ? (c - 'A' + 10) : -1;
|
||||
}
|
||||
|
||||
static int hexpair_to_int(const char *hexpair)
|
||||
{
|
||||
int n1 = hex_to_int(*hexpair);
|
||||
int n2 = hex_to_int(*(hexpair + 1));
|
||||
|
||||
if (n1 != -1 && n2 != -1) {
|
||||
return (n1 << 4) | n2;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_attribute_value_string(const char *s,
|
||||
int len,
|
||||
unsigned char *data,
|
||||
size_t *data_len)
|
||||
{
|
||||
const char *c;
|
||||
const char *end = s + len;
|
||||
unsigned char *d = data;
|
||||
int n;
|
||||
|
||||
for (c = s; c < end; c++) {
|
||||
if (*c == '\\') {
|
||||
c++;
|
||||
|
||||
/* Check for valid escaped characters as per RFC 4514 Section 3 */
|
||||
if (c + 1 < end && (n = hexpair_to_int(c)) != -1) {
|
||||
if (n == 0) {
|
||||
return MBEDTLS_ERR_X509_INVALID_NAME;
|
||||
}
|
||||
*(d++) = n;
|
||||
c++;
|
||||
} else if (c < end && strchr(" ,=+<>#;\"\\", *c)) {
|
||||
*(d++) = *c;
|
||||
} else {
|
||||
return MBEDTLS_ERR_X509_INVALID_NAME;
|
||||
}
|
||||
} else {
|
||||
*(d++) = *c;
|
||||
}
|
||||
|
||||
if (d - data == MBEDTLS_X509_MAX_DN_NAME_SIZE) {
|
||||
return MBEDTLS_ERR_X509_INVALID_NAME;
|
||||
}
|
||||
}
|
||||
*data_len = d - data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_attribute_value_der_encoded(const char *s,
|
||||
int len,
|
||||
unsigned char *data,
|
||||
size_t *data_len,
|
||||
int *tag)
|
||||
{
|
||||
const char *c = s;
|
||||
const char *end = c + len;
|
||||
unsigned char asn1_der_buf[MBEDTLS_X509_MAX_DN_NAME_SIZE];
|
||||
unsigned char *asn1_der_end;
|
||||
unsigned char *p;
|
||||
unsigned char *d = data;
|
||||
int n;
|
||||
|
||||
/* Converting from hexstring to raw binary so we can use asn1parse.c */
|
||||
if ((len < 5) || (*c != '#')) {
|
||||
return MBEDTLS_ERR_X509_INVALID_NAME;
|
||||
}
|
||||
c++;
|
||||
if ((*tag = hexpair_to_int(c)) == -1) {
|
||||
return MBEDTLS_ERR_X509_INVALID_NAME;
|
||||
}
|
||||
c += 2;
|
||||
p = asn1_der_buf;
|
||||
for (p = asn1_der_buf; c < end; c += 2) {
|
||||
if ((c + 1 >= end) || (n = hexpair_to_int(c)) == -1) {
|
||||
return MBEDTLS_ERR_X509_INVALID_NAME;
|
||||
}
|
||||
if (MBEDTLS_ASN1_IS_STRING_TAG(*tag) && n == 0) {
|
||||
return MBEDTLS_ERR_X509_INVALID_NAME;
|
||||
}
|
||||
*(p++) = n;
|
||||
}
|
||||
asn1_der_end = p;
|
||||
|
||||
p = asn1_der_buf;
|
||||
if (mbedtls_asn1_get_len(&p, asn1_der_end, data_len) != 0) {
|
||||
return MBEDTLS_ERR_X509_INVALID_NAME;
|
||||
}
|
||||
|
||||
while (p < asn1_der_end) {
|
||||
*(d++) = *(p++);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mbedtls_x509_string_to_names(mbedtls_asn1_named_data **head, const char *name)
|
||||
{
|
||||
int ret = MBEDTLS_ERR_X509_INVALID_NAME;
|
||||
int parse_ret = 0;
|
||||
const char *s = name, *c = s;
|
||||
const char *end = s + strlen(s);
|
||||
const char *oid = NULL;
|
||||
mbedtls_asn1_buf oid = { .p = NULL, .len = 0, .tag = MBEDTLS_ASN1_NULL };
|
||||
const x509_attr_descriptor_t *attr_descr = NULL;
|
||||
int in_tag = 1;
|
||||
char data[MBEDTLS_X509_MAX_DN_NAME_SIZE];
|
||||
char *d = data;
|
||||
int in_attr_type = 1;
|
||||
int tag;
|
||||
int numericoid = 0;
|
||||
unsigned char data[MBEDTLS_X509_MAX_DN_NAME_SIZE];
|
||||
size_t data_len = 0;
|
||||
|
||||
/* Clear existing chain if present */
|
||||
mbedtls_asn1_free_named_data_list(head);
|
||||
|
||||
while (c <= end) {
|
||||
if (in_tag && *c == '=') {
|
||||
if (in_attr_type && *c == '=') {
|
||||
if ((attr_descr = x509_attr_descr_from_name(s, c - s)) == NULL) {
|
||||
ret = MBEDTLS_ERR_X509_UNKNOWN_OID;
|
||||
goto exit;
|
||||
if ((mbedtls_oid_from_numeric_string(&oid, s, c - s)) != 0) {
|
||||
return MBEDTLS_ERR_X509_INVALID_NAME;
|
||||
} else {
|
||||
numericoid = 1;
|
||||
}
|
||||
} else {
|
||||
oid.len = strlen(attr_descr->oid);
|
||||
oid.p = mbedtls_calloc(1, oid.len);
|
||||
memcpy(oid.p, attr_descr->oid, oid.len);
|
||||
numericoid = 0;
|
||||
}
|
||||
|
||||
oid = attr_descr->oid;
|
||||
s = c + 1;
|
||||
in_tag = 0;
|
||||
d = data;
|
||||
in_attr_type = 0;
|
||||
}
|
||||
|
||||
if (!in_tag && *c == '\\' && c != end) {
|
||||
c++;
|
||||
|
||||
/* Check for valid escaped characters */
|
||||
if (c == end || *c != ',') {
|
||||
ret = MBEDTLS_ERR_X509_INVALID_NAME;
|
||||
goto exit;
|
||||
if (!in_attr_type && ((*c == ',' && *(c-1) != '\\') || c == end)) {
|
||||
if (s == c) {
|
||||
mbedtls_free(oid.p);
|
||||
return MBEDTLS_ERR_X509_INVALID_NAME;
|
||||
} else if (*s == '#') {
|
||||
if ((parse_ret =
|
||||
parse_attribute_value_der_encoded(s, (int) (c - s), data, &data_len,
|
||||
&tag)) != 0) {
|
||||
mbedtls_free(oid.p);
|
||||
return MBEDTLS_ERR_X509_INVALID_NAME;
|
||||
}
|
||||
} else {
|
||||
if (numericoid) {
|
||||
mbedtls_free(oid.p);
|
||||
return MBEDTLS_ERR_X509_INVALID_NAME;
|
||||
} else {
|
||||
if ((parse_ret =
|
||||
parse_attribute_value_string(s, (int) (c - s), data,
|
||||
&data_len)) != 0) {
|
||||
mbedtls_free(oid.p);
|
||||
return parse_ret;
|
||||
}
|
||||
tag = attr_descr->default_tag;
|
||||
}
|
||||
}
|
||||
} else if (!in_tag && (*c == ',' || c == end)) {
|
||||
mbedtls_asn1_named_data *cur =
|
||||
mbedtls_asn1_store_named_data(head, oid, strlen(oid),
|
||||
(unsigned char *) data,
|
||||
d - data);
|
||||
|
||||
mbedtls_asn1_named_data *cur =
|
||||
mbedtls_asn1_store_named_data(head, (char *) oid.p, oid.len,
|
||||
(unsigned char *) data,
|
||||
data_len);
|
||||
mbedtls_free(oid.p);
|
||||
oid.p = NULL;
|
||||
if (cur == NULL) {
|
||||
return MBEDTLS_ERR_X509_ALLOC_FAILED;
|
||||
}
|
||||
|
||||
// set tagType
|
||||
cur->val.tag = attr_descr->default_tag;
|
||||
cur->val.tag = tag;
|
||||
|
||||
while (c < end && *(c + 1) == ' ') {
|
||||
c++;
|
||||
}
|
||||
|
||||
s = c + 1;
|
||||
in_tag = 1;
|
||||
in_attr_type = 1;
|
||||
|
||||
/* Successfully parsed one name, update ret to success */
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (!in_tag && s != c + 1) {
|
||||
*(d++) = *c;
|
||||
|
||||
if (d - data == MBEDTLS_X509_MAX_DN_NAME_SIZE) {
|
||||
ret = MBEDTLS_ERR_X509_INVALID_NAME;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
c++;
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
if (oid.p != NULL) {
|
||||
mbedtls_free(oid.p);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user