From ba27e1c5a6997e6a9ff3f300cb3d9a05f5577bcc Mon Sep 17 00:00:00 2001 From: Fraser Tweedale Date: Thu, 18 Jan 2018 12:59:13 +1100 Subject: [PATCH] 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). --- src/csrgen-o.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++----- src/util.c | 14 ++++++++++++++ src/util.h | 13 +++++++++++++ 3 files changed, 75 insertions(+), 5 deletions(-) diff --git a/src/csrgen-o.c b/src/csrgen-o.c index b3f3775686d1a2518eaf5e9cbc0c0f3af34ba99a..86b2580fe74c3685327fc118ac7f8504b9c47bea 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 67143d523f80c2f18f4c2b15af16c41b86e1d405..0291510e210972250bbf4c1abd03c15459b43ad3 100644 --- a/src/util.c +++ b/src/util.c @@ -170,3 +170,17 @@ get_config_entry(char * in_data, const char *section, const char *key) free(data); 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 c1bcd0ab8b04c372e2eae42fe825577e8bb6f9ee..68fcde8d98d8690a9685ee9320d0244995eb0b9c 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 -- 2.14.3