From 47a60740b6aab81a221351094652d0ed3c09c568 Mon Sep 17 00:00:00 2001 From: Fraser Tweedale Date: Nov 21 2018 16:53:57 +0000 Subject: csrgen-o: handle multi-value RDNs and log dropped AVAs The existing procedure only took the first AVA from each RDN. Update the X509_NAME construction procedure to preserve multi-valued RDNs. X509_NAME_add_entry_by_txt() requires attribute short names ("CN", "O", etc) to be in upper case, otherwise it fails to add the attribute. Explicitly convert the user input to an Object ID (ASN1_OBJECT) and if it fails, upper case the string and retry. Log when an AVA cannot be added to the X509_NAME (typically because the attribute type is not recognised). --- diff --git a/src/csrgen-o.c b/src/csrgen-o.c index b3f3775..86b2580 100644 --- a/src/csrgen-o.c +++ b/src/csrgen-o.c @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -51,6 +52,7 @@ #include "subproc.h" #include "util-m.h" #include "util-o.h" +#include "util.h" struct cm_csrgen_state { struct cm_csrgen_state_pvt pvt; @@ -205,12 +207,53 @@ cm_csrgen_o_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry, if (ret == LDAP_SUCCESS) { for (i = 0; dn[i] != NULL; i++) { rdn = dn[i]; + int set = 0; // add next AVA in new RDN + for (int j = 0; rdn[j] != NULL; j++) { + attr = rdn[j]; - attr = rdn[0]; - X509_NAME_add_entry_by_txt(subject, - attr->la_attr.bv_val, astring_type(attr->la_attr.bv_val, attr->la_value.bv_val, attr->la_value.bv_len), - (unsigned char *) attr->la_value.bv_val, attr->la_value.bv_len, - -1, 0); + // process attribute type + ASN1_OBJECT *obj = OBJ_txt2obj( + attr->la_attr.bv_val, + 0 /* allow dotted OIDs */); + if (obj == NULL) { + // OpenSSL requires upper-cased short names + // i.e. "CN", "O", etc. + // Convert to upper and try again. + char *attr_upper = str_to_upper(attr->la_attr.bv_val); + if (attr_upper != NULL) { + obj = OBJ_txt2obj(attr_upper, 0); + free(attr_upper); + } + } + + if (obj == NULL) { + cm_log( + 0, + "Unrecognised attribute type: (%s). Continuing.\n", + attr->la_attr.bv_val); + } else { + ret = X509_NAME_add_entry_by_OBJ( + subject, + obj, + astring_type( + attr->la_attr.bv_val, + attr->la_value.bv_val, + attr->la_value.bv_len), + (unsigned char *) attr->la_value.bv_val, + attr->la_value.bv_len, + -1, // append to RDN + set); + if (ret == 1) { + set = -1; // add next AVA to previous RDN + } else { + cm_log( + 0, + "Failed to add AVA to CSR: (%s=%s). Continuing.\n", + attr->la_attr.bv_val, + attr->la_value.bv_val); + } + } + } } if (dn != NULL) ldap_dnfree(dn); diff --git a/src/util.c b/src/util.c index 373bb53..28e2d0d 100644 --- a/src/util.c +++ b/src/util.c @@ -176,3 +176,17 @@ get_config_entry(char * in_data, const char *section, const char *key) free(tmp); return NULL; } + +void str_to_upper_inplace(char *s) { + if (NULL == s) return; + for (; *s != '\0'; s++) { + *s = toupper(*s); + } +} + +char *str_to_upper(const char *s) { + char *ret = strdup(s); + if (ret != NULL) + str_to_upper_inplace(ret); + return ret; +} diff --git a/src/util.h b/src/util.h index c1bcd0a..68fcde8 100644 --- a/src/util.h +++ b/src/util.h @@ -21,4 +21,17 @@ char *read_config_file(const char *filename); char *get_config_entry(char *data, const char *section, const char *key); +/* + * Convert string to upper case in place. + * String must be null-terminated. Locale-unaware. + */ +void str_to_upper_inplace(char *s); + +/* + * Return upper-cased copy of string. + * String must be null-terminated. Locale-unaware. + * Return NULL on error (insufficient memory). + */ +char *str_to_upper(const char *s); + #endif