Add a certificate exercising all supported SAN types
This will be used for comparison in unit tests.
Add a possibility to write certificates with SAN
in cert_write.
Signed-off-by: Andrzej Kurek <andrzej.kurek@arm.com>
diff --git a/programs/x509/cert_write.c b/programs/x509/cert_write.c
index 51b09f3..ac6187a 100644
--- a/programs/x509/cert_write.c
+++ b/programs/x509/cert_write.c
@@ -79,6 +79,7 @@
#define DFL_NOT_AFTER "20301231235959"
#define DFL_SERIAL "1"
#define DFL_SERIAL_HEX "1"
+#define DFL_EXT_SUBJECTALTNAME ""
#define DFL_SELFSIGN 0
#define DFL_IS_CA 0
#define DFL_MAX_PATHLEN -1
@@ -134,6 +135,13 @@
" subject_identifier=%%s default: 1\n" \
" Possible values: 0, 1\n" \
" (Considered for v3 only)\n" \
+ " san=%%s default: (none)\n" \
+ " Comma-separated-list of values:\n" \
+ " DNS:value\n" \
+ " URI:value\n" \
+ " RFC822:value\n" \
+ " IP:value (Only IPv4 is supported)\n" \
+ " DN:value\n" \
" authority_identifier=%%s default: 1\n" \
" Possible values: 0, 1\n" \
" (Considered for v3 only)\n" \
@@ -188,6 +196,7 @@
const char *issuer_pwd; /* password for the issuer key file */
const char *output_file; /* where to store the constructed CRT */
const char *subject_name; /* subject name for certificate */
+ mbedtls_x509_san_list *san_list; /* subjectAltName for certificate */
const char *issuer_name; /* issuer name for certificate */
const char *not_before; /* validity period not before */
const char *not_after; /* validity period not after */
@@ -207,6 +216,19 @@
int format; /* format */
} opt;
+static int ip_string_to_bytes(const char *str, uint8_t *bytes, int maxBytes)
+{
+ for (int i = 0; i < maxBytes; i++) {
+ bytes[i] = strtoul(str, NULL, 16);
+ str = strchr(str, '.');
+ if (str == NULL || *str == '\0') {
+ break;
+ }
+ str++;
+ }
+ return 0;
+}
+
int write_certificate(mbedtls_x509write_cert *crt, const char *output_file,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng)
@@ -301,7 +323,7 @@
char buf[1024];
char issuer_name[256];
int i;
- char *p, *q, *r;
+ char *p, *q, *r, *r2;
#if defined(MBEDTLS_X509_CSR_PARSE_C)
char subject_name[256];
mbedtls_x509_csr csr;
@@ -314,7 +336,8 @@
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
const char *pers = "crt example app";
-
+ mbedtls_x509_san_list *cur, *prev;
+ uint8_t ip[4] = { 0 };
/*
* Set to sane values
*/
@@ -370,6 +393,7 @@
opt.authority_identifier = DFL_AUTH_IDENT;
opt.basic_constraints = DFL_CONSTRAINTS;
opt.format = DFL_FORMAT;
+ opt.san_list = NULL;
for (i = 1; i < argc; i++) {
@@ -528,6 +552,69 @@
q = r;
}
+ } else if (strcmp(p, "san") == 0) {
+ prev = NULL;
+
+ while (q != NULL) {
+ if ((r = strchr(q, ';')) != NULL) {
+ *r++ = '\0';
+ }
+
+ cur = mbedtls_calloc(1, sizeof(mbedtls_x509_san_list));
+ if (cur == NULL) {
+ mbedtls_printf("Not enough memory for subjectAltName list\n");
+ goto usage;
+ }
+
+ cur->next = NULL;
+
+ if ((r2 = strchr(q, ':')) != NULL) {
+ *r2++ = '\0';
+ }
+ if (strcmp(q, "RFC822") == 0) {
+ cur->node.type = MBEDTLS_X509_SAN_RFC822_NAME;
+ } else if (strcmp(q, "URI") == 0) {
+ cur->node.type = MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER;
+ } else if (strcmp(q, "DNS") == 0) {
+ cur->node.type = MBEDTLS_X509_SAN_DNS_NAME;
+ } else if (strcmp(q, "IP") == 0) {
+ cur->node.type = MBEDTLS_X509_SAN_IP_ADDRESS;
+ ip_string_to_bytes(r2, ip, 4);
+ cur->node.san.unstructured_name.p = (unsigned char *) ip;
+ cur->node.san.unstructured_name.len = sizeof(ip);
+ } else if (strcmp(q, "DN") == 0) {
+ mbedtls_asn1_named_data *ext_san_dirname = NULL;
+ cur->node.type = MBEDTLS_X509_SAN_DIRECTORY_NAME;
+ if ((ret = mbedtls_x509_string_to_names(&ext_san_dirname,
+ r2)) != 0) {
+ mbedtls_strerror(ret, buf, sizeof(buf));
+ mbedtls_printf(
+ " failed\n ! mbedtls_x509_string_to_names "
+ "returned -0x%04x - %s\n\n",
+ (unsigned int) -ret, buf);
+ goto exit;
+ }
+ cur->node.san.directory_name = *ext_san_dirname;
+ } else {
+ mbedtls_free(cur);
+ goto usage;
+ }
+
+ if (strcmp(q, "IP") != 0 && strcmp(q, "DN") != 0) {
+ q = r2;
+ cur->node.san.unstructured_name.p = (unsigned char *) q;
+ cur->node.san.unstructured_name.len = strlen(q);
+ }
+
+ if (prev == NULL) {
+ opt.san_list = cur;
+ } else {
+ prev->next = cur;
+ }
+
+ prev = cur;
+ q = r;
+ }
} else if (strcmp(p, "ns_cert_type") == 0) {
while (q != NULL) {
if ((r = strchr(q, ',')) != NULL) {
@@ -833,6 +920,17 @@
mbedtls_printf(" ok\n");
}
+ if (opt.san_list != NULL) {
+ ret = mbedtls_x509write_crt_set_subject_alternative_name(&crt, opt.san_list);
+
+ if (ret != 0) {
+ mbedtls_printf(
+ " failed\n ! mbedtls_x509write_csr_set_subject_alternative_name returned %d",
+ ret);
+ goto exit;
+ }
+ }
+
if (opt.ext_key_usage) {
mbedtls_printf(" . Adding the Extended Key Usage extension ...");
fflush(stdout);