1178825Sdfr/* 2233294Sstas * Copyright (c) 2004 - 2009 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 5178825Sdfr * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 9178825Sdfr * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 12178825Sdfr * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 16178825Sdfr * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 20178825Sdfr * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 32178825Sdfr */ 33178825Sdfr 34178825Sdfr#include "hx_locl.h" 35233294Sstas#include <wind.h> 36233294Sstas#include "char_map.h" 37178825Sdfr 38178825Sdfr/** 39178825Sdfr * @page page_name PKIX/X.509 Names 40178825Sdfr * 41178825Sdfr * There are several names in PKIX/X.509, GeneralName and Name. 42178825Sdfr * 43178825Sdfr * A Name consists of an ordered list of Relative Distinguished Names 44178825Sdfr * (RDN). Each RDN consists of an unordered list of typed strings. The 45178825Sdfr * types are defined by OID and have long and short description. For 46178825Sdfr * example id-at-commonName (2.5.4.3) have the long name CommonName 47233294Sstas * and short name CN. The string itself can be of several encoding, 48178825Sdfr * UTF8, UTF16, Teltex string, etc. The type limit what encoding 49178825Sdfr * should be used. 50178825Sdfr * 51178825Sdfr * GeneralName is a broader nametype that can contains al kind of 52178825Sdfr * stuff like Name, IP addresses, partial Name, etc. 53178825Sdfr * 54178825Sdfr * Name is mapped into a hx509_name object. 55178825Sdfr * 56178825Sdfr * Parse and string name into a hx509_name object with hx509_parse_name(), 57178825Sdfr * make it back into string representation with hx509_name_to_string(). 58178825Sdfr * 59178825Sdfr * Name string are defined rfc2253, rfc1779 and X.501. 60178825Sdfr * 61178825Sdfr * See the library functions here: @ref hx509_name 62178825Sdfr */ 63178825Sdfr 64178825Sdfrstatic const struct { 65178825Sdfr const char *n; 66233294Sstas const heim_oid *o; 67233294Sstas wind_profile_flags flags; 68178825Sdfr} no[] = { 69233294Sstas { "C", &asn1_oid_id_at_countryName, 0 }, 70233294Sstas { "CN", &asn1_oid_id_at_commonName, 0 }, 71233294Sstas { "DC", &asn1_oid_id_domainComponent, 0 }, 72233294Sstas { "L", &asn1_oid_id_at_localityName, 0 }, 73233294Sstas { "O", &asn1_oid_id_at_organizationName, 0 }, 74233294Sstas { "OU", &asn1_oid_id_at_organizationalUnitName, 0 }, 75233294Sstas { "S", &asn1_oid_id_at_stateOrProvinceName, 0 }, 76233294Sstas { "STREET", &asn1_oid_id_at_streetAddress, 0 }, 77233294Sstas { "UID", &asn1_oid_id_Userid, 0 }, 78233294Sstas { "emailAddress", &asn1_oid_id_pkcs9_emailAddress, 0 }, 79233294Sstas { "serialNumber", &asn1_oid_id_at_serialNumber, 0 } 80178825Sdfr}; 81178825Sdfr 82178825Sdfrstatic char * 83233294Sstasquote_string(const char *f, size_t len, int flags, size_t *rlen) 84178825Sdfr{ 85178825Sdfr size_t i, j, tolen; 86233294Sstas const unsigned char *from = (const unsigned char *)f; 87233294Sstas unsigned char *to; 88178825Sdfr 89178825Sdfr tolen = len * 3 + 1; 90178825Sdfr to = malloc(tolen); 91178825Sdfr if (to == NULL) 92178825Sdfr return NULL; 93178825Sdfr 94178825Sdfr for (i = 0, j = 0; i < len; i++) { 95233294Sstas unsigned char map = char_map[from[i]] & flags; 96233294Sstas if (i == 0 && (map & Q_RFC2253_QUOTE_FIRST)) { 97233294Sstas to[j++] = '\\'; 98178825Sdfr to[j++] = from[i]; 99233294Sstas } else if ((i + 1) == len && (map & Q_RFC2253_QUOTE_LAST)) { 100233294Sstas 101178825Sdfr to[j++] = '\\'; 102178825Sdfr to[j++] = from[i]; 103233294Sstas } else if (map & Q_RFC2253_QUOTE) { 104233294Sstas to[j++] = '\\'; 105178825Sdfr to[j++] = from[i]; 106233294Sstas } else if (map & Q_RFC2253_HEX) { 107233294Sstas int l = snprintf((char *)&to[j], tolen - j - 1, 108178825Sdfr "#%02x", (unsigned char)from[i]); 109178825Sdfr j += l; 110233294Sstas } else { 111233294Sstas to[j++] = from[i]; 112178825Sdfr } 113178825Sdfr } 114178825Sdfr to[j] = '\0'; 115178825Sdfr assert(j < tolen); 116178825Sdfr *rlen = j; 117233294Sstas return (char *)to; 118178825Sdfr} 119178825Sdfr 120178825Sdfr 121178825Sdfrstatic int 122233294Sstasappend_string(char **str, size_t *total_len, const char *ss, 123178825Sdfr size_t len, int quote) 124178825Sdfr{ 125178825Sdfr char *s, *qs; 126178825Sdfr 127178825Sdfr if (quote) 128233294Sstas qs = quote_string(ss, len, Q_RFC2253, &len); 129178825Sdfr else 130178825Sdfr qs = rk_UNCONST(ss); 131178825Sdfr 132178825Sdfr s = realloc(*str, len + *total_len + 1); 133178825Sdfr if (s == NULL) 134178825Sdfr _hx509_abort("allocation failure"); /* XXX */ 135178825Sdfr memcpy(s + *total_len, qs, len); 136178825Sdfr if (qs != ss) 137178825Sdfr free(qs); 138178825Sdfr s[*total_len + len] = '\0'; 139178825Sdfr *str = s; 140178825Sdfr *total_len += len; 141178825Sdfr return 0; 142178825Sdfr} 143178825Sdfr 144178825Sdfrstatic char * 145178825Sdfroidtostring(const heim_oid *type) 146178825Sdfr{ 147178825Sdfr char *s; 148178825Sdfr size_t i; 149233294Sstas 150178825Sdfr for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) { 151233294Sstas if (der_heim_oid_cmp(no[i].o, type) == 0) 152178825Sdfr return strdup(no[i].n); 153178825Sdfr } 154178825Sdfr if (der_print_heim_oid(type, '.', &s) != 0) 155178825Sdfr return NULL; 156178825Sdfr return s; 157178825Sdfr} 158178825Sdfr 159178825Sdfrstatic int 160178825Sdfrstringtooid(const char *name, size_t len, heim_oid *oid) 161178825Sdfr{ 162233294Sstas int ret; 163233294Sstas size_t i; 164178825Sdfr char *s; 165233294Sstas 166178825Sdfr memset(oid, 0, sizeof(*oid)); 167178825Sdfr 168178825Sdfr for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) { 169178825Sdfr if (strncasecmp(no[i].n, name, len) == 0) 170233294Sstas return der_copy_oid(no[i].o, oid); 171178825Sdfr } 172178825Sdfr s = malloc(len + 1); 173178825Sdfr if (s == NULL) 174178825Sdfr return ENOMEM; 175178825Sdfr memcpy(s, name, len); 176178825Sdfr s[len] = '\0'; 177178825Sdfr ret = der_parse_heim_oid(s, ".", oid); 178178825Sdfr free(s); 179178825Sdfr return ret; 180178825Sdfr} 181178825Sdfr 182178825Sdfr/** 183178825Sdfr * Convert the hx509 name object into a printable string. 184178825Sdfr * The resulting string should be freed with free(). 185178825Sdfr * 186178825Sdfr * @param name name to print 187178825Sdfr * @param str the string to return 188178825Sdfr * 189178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 190178825Sdfr * 191178825Sdfr * @ingroup hx509_name 192178825Sdfr */ 193178825Sdfr 194178825Sdfrint 195178825Sdfrhx509_name_to_string(const hx509_name name, char **str) 196178825Sdfr{ 197178825Sdfr return _hx509_Name_to_string(&name->der_name, str); 198178825Sdfr} 199178825Sdfr 200178825Sdfrint 201178825Sdfr_hx509_Name_to_string(const Name *n, char **str) 202178825Sdfr{ 203178825Sdfr size_t total_len = 0; 204233294Sstas size_t i, j, m; 205233294Sstas int ret; 206178825Sdfr 207178825Sdfr *str = strdup(""); 208178825Sdfr if (*str == NULL) 209178825Sdfr return ENOMEM; 210178825Sdfr 211233294Sstas for (m = n->u.rdnSequence.len; m > 0; m--) { 212233294Sstas size_t len; 213233294Sstas i = m - 1; 214178825Sdfr 215178825Sdfr for (j = 0; j < n->u.rdnSequence.val[i].len; j++) { 216178825Sdfr DirectoryString *ds = &n->u.rdnSequence.val[i].val[j].value; 217178825Sdfr char *oidname; 218178825Sdfr char *ss; 219233294Sstas 220178825Sdfr oidname = oidtostring(&n->u.rdnSequence.val[i].val[j].type); 221178825Sdfr 222178825Sdfr switch(ds->element) { 223178825Sdfr case choice_DirectoryString_ia5String: 224233294Sstas ss = ds->u.ia5String.data; 225233294Sstas len = ds->u.ia5String.length; 226178825Sdfr break; 227178825Sdfr case choice_DirectoryString_printableString: 228233294Sstas ss = ds->u.printableString.data; 229233294Sstas len = ds->u.printableString.length; 230178825Sdfr break; 231178825Sdfr case choice_DirectoryString_utf8String: 232178825Sdfr ss = ds->u.utf8String; 233233294Sstas len = strlen(ss); 234178825Sdfr break; 235178825Sdfr case choice_DirectoryString_bmpString: { 236233294Sstas const uint16_t *bmp = ds->u.bmpString.data; 237178825Sdfr size_t bmplen = ds->u.bmpString.length; 238178825Sdfr size_t k; 239178825Sdfr 240233294Sstas ret = wind_ucs2utf8_length(bmp, bmplen, &k); 241233294Sstas if (ret) 242233294Sstas return ret; 243233294Sstas 244233294Sstas ss = malloc(k + 1); 245178825Sdfr if (ss == NULL) 246178825Sdfr _hx509_abort("allocation failure"); /* XXX */ 247233294Sstas ret = wind_ucs2utf8(bmp, bmplen, ss, NULL); 248233294Sstas if (ret) { 249233294Sstas free(ss); 250233294Sstas return ret; 251233294Sstas } 252178825Sdfr ss[k] = '\0'; 253233294Sstas len = k; 254178825Sdfr break; 255178825Sdfr } 256178825Sdfr case choice_DirectoryString_teletexString: 257233294Sstas ss = ds->u.teletexString; 258233294Sstas len = strlen(ss); 259178825Sdfr break; 260178825Sdfr case choice_DirectoryString_universalString: { 261233294Sstas const uint32_t *uni = ds->u.universalString.data; 262178825Sdfr size_t unilen = ds->u.universalString.length; 263178825Sdfr size_t k; 264178825Sdfr 265233294Sstas ret = wind_ucs4utf8_length(uni, unilen, &k); 266233294Sstas if (ret) 267233294Sstas return ret; 268233294Sstas 269233294Sstas ss = malloc(k + 1); 270178825Sdfr if (ss == NULL) 271178825Sdfr _hx509_abort("allocation failure"); /* XXX */ 272233294Sstas ret = wind_ucs4utf8(uni, unilen, ss, NULL); 273233294Sstas if (ret) { 274233294Sstas free(ss); 275233294Sstas return ret; 276233294Sstas } 277178825Sdfr ss[k] = '\0'; 278233294Sstas len = k; 279178825Sdfr break; 280178825Sdfr } 281178825Sdfr default: 282178825Sdfr _hx509_abort("unknown directory type: %d", ds->element); 283178825Sdfr exit(1); 284178825Sdfr } 285178825Sdfr append_string(str, &total_len, oidname, strlen(oidname), 0); 286178825Sdfr free(oidname); 287178825Sdfr append_string(str, &total_len, "=", 1, 0); 288178825Sdfr append_string(str, &total_len, ss, len, 1); 289233294Sstas if (ds->element == choice_DirectoryString_bmpString || 290233294Sstas ds->element == choice_DirectoryString_universalString) 291178825Sdfr { 292178825Sdfr free(ss); 293178825Sdfr } 294178825Sdfr if (j + 1 < n->u.rdnSequence.val[i].len) 295178825Sdfr append_string(str, &total_len, "+", 1, 0); 296178825Sdfr } 297178825Sdfr 298178825Sdfr if (i > 0) 299178825Sdfr append_string(str, &total_len, ",", 1, 0); 300178825Sdfr } 301178825Sdfr return 0; 302178825Sdfr} 303178825Sdfr 304233294Sstas#define COPYCHARARRAY(_ds,_el,_l,_n) \ 305233294Sstas (_l) = strlen(_ds->u._el); \ 306233294Sstas (_n) = malloc((_l) * sizeof((_n)[0])); \ 307233294Sstas if ((_n) == NULL) \ 308233294Sstas return ENOMEM; \ 309233294Sstas for (i = 0; i < (_l); i++) \ 310233294Sstas (_n)[i] = _ds->u._el[i] 311178825Sdfr 312178825Sdfr 313233294Sstas#define COPYVALARRAY(_ds,_el,_l,_n) \ 314233294Sstas (_l) = _ds->u._el.length; \ 315233294Sstas (_n) = malloc((_l) * sizeof((_n)[0])); \ 316233294Sstas if ((_n) == NULL) \ 317233294Sstas return ENOMEM; \ 318233294Sstas for (i = 0; i < (_l); i++) \ 319233294Sstas (_n)[i] = _ds->u._el.data[i] 320233294Sstas 321233294Sstas#define COPYVOIDARRAY(_ds,_el,_l,_n) \ 322233294Sstas (_l) = _ds->u._el.length; \ 323233294Sstas (_n) = malloc((_l) * sizeof((_n)[0])); \ 324233294Sstas if ((_n) == NULL) \ 325233294Sstas return ENOMEM; \ 326233294Sstas for (i = 0; i < (_l); i++) \ 327233294Sstas (_n)[i] = ((unsigned char *)_ds->u._el.data)[i] 328233294Sstas 329233294Sstas 330233294Sstas 331233294Sstasstatic int 332233294Sstasdsstringprep(const DirectoryString *ds, uint32_t **rname, size_t *rlen) 333178825Sdfr{ 334233294Sstas wind_profile_flags flags; 335233294Sstas size_t i, len; 336233294Sstas int ret; 337233294Sstas uint32_t *name; 338178825Sdfr 339233294Sstas *rname = NULL; 340233294Sstas *rlen = 0; 341178825Sdfr 342233294Sstas switch(ds->element) { 343178825Sdfr case choice_DirectoryString_ia5String: 344233294Sstas flags = WIND_PROFILE_LDAP; 345233294Sstas COPYVOIDARRAY(ds, ia5String, len, name); 346178825Sdfr break; 347233294Sstas case choice_DirectoryString_printableString: 348233294Sstas flags = WIND_PROFILE_LDAP; 349233294Sstas flags |= WIND_PROFILE_LDAP_CASE_EXACT_ATTRIBUTE; 350233294Sstas COPYVOIDARRAY(ds, printableString, len, name); 351233294Sstas break; 352178825Sdfr case choice_DirectoryString_teletexString: 353233294Sstas flags = WIND_PROFILE_LDAP_CASE; 354233294Sstas COPYCHARARRAY(ds, teletexString, len, name); 355178825Sdfr break; 356233294Sstas case choice_DirectoryString_bmpString: 357233294Sstas flags = WIND_PROFILE_LDAP; 358233294Sstas COPYVALARRAY(ds, bmpString, len, name); 359178825Sdfr break; 360178825Sdfr case choice_DirectoryString_universalString: 361233294Sstas flags = WIND_PROFILE_LDAP; 362233294Sstas COPYVALARRAY(ds, universalString, len, name); 363178825Sdfr break; 364233294Sstas case choice_DirectoryString_utf8String: 365233294Sstas flags = WIND_PROFILE_LDAP; 366233294Sstas ret = wind_utf8ucs4_length(ds->u.utf8String, &len); 367233294Sstas if (ret) 368233294Sstas return ret; 369233294Sstas name = malloc(len * sizeof(name[0])); 370233294Sstas if (name == NULL) 371233294Sstas return ENOMEM; 372233294Sstas ret = wind_utf8ucs4(ds->u.utf8String, name, &len); 373233294Sstas if (ret) { 374233294Sstas free(name); 375233294Sstas return ret; 376233294Sstas } 377178825Sdfr break; 378178825Sdfr default: 379233294Sstas _hx509_abort("unknown directory type: %d", ds->element); 380178825Sdfr } 381233294Sstas 382233294Sstas *rlen = len; 383233294Sstas /* try a couple of times to get the length right, XXX gross */ 384233294Sstas for (i = 0; i < 4; i++) { 385233294Sstas *rlen = *rlen * 2; 386233294Sstas *rname = malloc(*rlen * sizeof((*rname)[0])); 387233294Sstas 388233294Sstas ret = wind_stringprep(name, len, *rname, rlen, flags); 389233294Sstas if (ret == WIND_ERR_OVERRUN) { 390233294Sstas free(*rname); 391233294Sstas *rname = NULL; 392233294Sstas continue; 393233294Sstas } else 394233294Sstas break; 395233294Sstas } 396233294Sstas free(name); 397233294Sstas if (ret) { 398233294Sstas if (*rname) 399233294Sstas free(*rname); 400233294Sstas *rname = NULL; 401233294Sstas *rlen = 0; 402233294Sstas return ret; 403233294Sstas } 404233294Sstas 405233294Sstas return 0; 406178825Sdfr} 407178825Sdfr 408178825Sdfrint 409233294Sstas_hx509_name_ds_cmp(const DirectoryString *ds1, 410233294Sstas const DirectoryString *ds2, 411233294Sstas int *diff) 412178825Sdfr{ 413233294Sstas uint32_t *ds1lp, *ds2lp; 414233294Sstas size_t ds1len, ds2len, i; 415233294Sstas int ret; 416178825Sdfr 417233294Sstas ret = dsstringprep(ds1, &ds1lp, &ds1len); 418233294Sstas if (ret) 419233294Sstas return ret; 420233294Sstas ret = dsstringprep(ds2, &ds2lp, &ds2len); 421233294Sstas if (ret) { 422233294Sstas free(ds1lp); 423233294Sstas return ret; 424233294Sstas } 425178825Sdfr 426233294Sstas if (ds1len != ds2len) 427233294Sstas *diff = ds1len - ds2len; 428233294Sstas else { 429233294Sstas for (i = 0; i < ds1len; i++) { 430233294Sstas *diff = ds1lp[i] - ds2lp[i]; 431233294Sstas if (*diff) 432233294Sstas break; 433233294Sstas } 434233294Sstas } 435233294Sstas free(ds1lp); 436233294Sstas free(ds2lp); 437233294Sstas 438233294Sstas return 0; 439233294Sstas} 440233294Sstas 441233294Sstasint 442233294Sstas_hx509_name_cmp(const Name *n1, const Name *n2, int *c) 443233294Sstas{ 444233294Sstas int ret; 445233294Sstas size_t i, j; 446233294Sstas 447233294Sstas *c = n1->u.rdnSequence.len - n2->u.rdnSequence.len; 448233294Sstas if (*c) 449233294Sstas return 0; 450233294Sstas 451178825Sdfr for (i = 0 ; i < n1->u.rdnSequence.len; i++) { 452233294Sstas *c = n1->u.rdnSequence.val[i].len - n2->u.rdnSequence.val[i].len; 453233294Sstas if (*c) 454233294Sstas return 0; 455178825Sdfr 456178825Sdfr for (j = 0; j < n1->u.rdnSequence.val[i].len; j++) { 457233294Sstas *c = der_heim_oid_cmp(&n1->u.rdnSequence.val[i].val[j].type, 458233294Sstas &n1->u.rdnSequence.val[i].val[j].type); 459233294Sstas if (*c) 460233294Sstas return 0; 461233294Sstas 462233294Sstas ret = _hx509_name_ds_cmp(&n1->u.rdnSequence.val[i].val[j].value, 463233294Sstas &n2->u.rdnSequence.val[i].val[j].value, 464233294Sstas c); 465233294Sstas if (ret) 466233294Sstas return ret; 467233294Sstas if (*c) 468233294Sstas return 0; 469178825Sdfr } 470178825Sdfr } 471233294Sstas *c = 0; 472178825Sdfr return 0; 473178825Sdfr} 474178825Sdfr 475178825Sdfr/** 476178825Sdfr * Compare to hx509 name object, useful for sorting. 477178825Sdfr * 478178825Sdfr * @param n1 a hx509 name object. 479178825Sdfr * @param n2 a hx509 name object. 480178825Sdfr * 481178825Sdfr * @return 0 the objects are the same, returns > 0 is n2 is "larger" 482178825Sdfr * then n2, < 0 if n1 is "smaller" then n2. 483178825Sdfr * 484178825Sdfr * @ingroup hx509_name 485178825Sdfr */ 486178825Sdfr 487178825Sdfrint 488178825Sdfrhx509_name_cmp(hx509_name n1, hx509_name n2) 489178825Sdfr{ 490233294Sstas int ret, diff; 491233294Sstas ret = _hx509_name_cmp(&n1->der_name, &n2->der_name, &diff); 492233294Sstas if (ret) 493233294Sstas return ret; 494233294Sstas return diff; 495178825Sdfr} 496178825Sdfr 497178825Sdfr 498178825Sdfrint 499178825Sdfr_hx509_name_from_Name(const Name *n, hx509_name *name) 500178825Sdfr{ 501178825Sdfr int ret; 502178825Sdfr *name = calloc(1, sizeof(**name)); 503178825Sdfr if (*name == NULL) 504178825Sdfr return ENOMEM; 505178825Sdfr ret = copy_Name(n, &(*name)->der_name); 506178825Sdfr if (ret) { 507178825Sdfr free(*name); 508178825Sdfr *name = NULL; 509178825Sdfr } 510178825Sdfr return ret; 511178825Sdfr} 512178825Sdfr 513178825Sdfrint 514178825Sdfr_hx509_name_modify(hx509_context context, 515233294Sstas Name *name, 516178825Sdfr int append, 517233294Sstas const heim_oid *oid, 518178825Sdfr const char *str) 519178825Sdfr{ 520178825Sdfr RelativeDistinguishedName *rdn; 521178825Sdfr int ret; 522178825Sdfr void *ptr; 523178825Sdfr 524233294Sstas ptr = realloc(name->u.rdnSequence.val, 525233294Sstas sizeof(name->u.rdnSequence.val[0]) * 526178825Sdfr (name->u.rdnSequence.len + 1)); 527178825Sdfr if (ptr == NULL) { 528178825Sdfr hx509_set_error_string(context, 0, ENOMEM, "Out of memory"); 529178825Sdfr return ENOMEM; 530178825Sdfr } 531178825Sdfr name->u.rdnSequence.val = ptr; 532178825Sdfr 533178825Sdfr if (append) { 534178825Sdfr rdn = &name->u.rdnSequence.val[name->u.rdnSequence.len]; 535178825Sdfr } else { 536178825Sdfr memmove(&name->u.rdnSequence.val[1], 537178825Sdfr &name->u.rdnSequence.val[0], 538233294Sstas name->u.rdnSequence.len * 539178825Sdfr sizeof(name->u.rdnSequence.val[0])); 540233294Sstas 541178825Sdfr rdn = &name->u.rdnSequence.val[0]; 542178825Sdfr } 543178825Sdfr rdn->val = malloc(sizeof(rdn->val[0])); 544178825Sdfr if (rdn->val == NULL) 545178825Sdfr return ENOMEM; 546178825Sdfr rdn->len = 1; 547178825Sdfr ret = der_copy_oid(oid, &rdn->val[0].type); 548178825Sdfr if (ret) 549178825Sdfr return ret; 550178825Sdfr rdn->val[0].value.element = choice_DirectoryString_utf8String; 551178825Sdfr rdn->val[0].value.u.utf8String = strdup(str); 552178825Sdfr if (rdn->val[0].value.u.utf8String == NULL) 553178825Sdfr return ENOMEM; 554178825Sdfr name->u.rdnSequence.len += 1; 555178825Sdfr 556178825Sdfr return 0; 557178825Sdfr} 558178825Sdfr 559178825Sdfr/** 560178825Sdfr * Parse a string into a hx509 name object. 561178825Sdfr * 562178825Sdfr * @param context A hx509 context. 563178825Sdfr * @param str a string to parse. 564178825Sdfr * @param name the resulting object, NULL in case of error. 565178825Sdfr * 566178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 567178825Sdfr * 568178825Sdfr * @ingroup hx509_name 569178825Sdfr */ 570178825Sdfr 571178825Sdfrint 572178825Sdfrhx509_parse_name(hx509_context context, const char *str, hx509_name *name) 573178825Sdfr{ 574178825Sdfr const char *p, *q; 575178825Sdfr size_t len; 576178825Sdfr hx509_name n; 577178825Sdfr int ret; 578178825Sdfr 579178825Sdfr *name = NULL; 580178825Sdfr 581178825Sdfr n = calloc(1, sizeof(*n)); 582178825Sdfr if (n == NULL) { 583178825Sdfr hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 584178825Sdfr return ENOMEM; 585178825Sdfr } 586178825Sdfr 587178825Sdfr n->der_name.element = choice_Name_rdnSequence; 588178825Sdfr 589178825Sdfr p = str; 590178825Sdfr 591178825Sdfr while (p != NULL && *p != '\0') { 592178825Sdfr heim_oid oid; 593178825Sdfr int last; 594178825Sdfr 595178825Sdfr q = strchr(p, ','); 596178825Sdfr if (q) { 597178825Sdfr len = (q - p); 598178825Sdfr last = 1; 599178825Sdfr } else { 600178825Sdfr len = strlen(p); 601178825Sdfr last = 0; 602178825Sdfr } 603178825Sdfr 604178825Sdfr q = strchr(p, '='); 605178825Sdfr if (q == NULL) { 606178825Sdfr ret = HX509_PARSING_NAME_FAILED; 607178825Sdfr hx509_set_error_string(context, 0, ret, "missing = in %s", p); 608178825Sdfr goto out; 609178825Sdfr } 610178825Sdfr if (q == p) { 611178825Sdfr ret = HX509_PARSING_NAME_FAILED; 612233294Sstas hx509_set_error_string(context, 0, ret, 613178825Sdfr "missing name before = in %s", p); 614178825Sdfr goto out; 615178825Sdfr } 616233294Sstas 617233294Sstas if ((size_t)(q - p) > len) { 618178825Sdfr ret = HX509_PARSING_NAME_FAILED; 619178825Sdfr hx509_set_error_string(context, 0, ret, " = after , in %s", p); 620178825Sdfr goto out; 621178825Sdfr } 622178825Sdfr 623178825Sdfr ret = stringtooid(p, q - p, &oid); 624178825Sdfr if (ret) { 625178825Sdfr ret = HX509_PARSING_NAME_FAILED; 626233294Sstas hx509_set_error_string(context, 0, ret, 627178825Sdfr "unknown type: %.*s", (int)(q - p), p); 628178825Sdfr goto out; 629178825Sdfr } 630233294Sstas 631178825Sdfr { 632178825Sdfr size_t pstr_len = len - (q - p) - 1; 633178825Sdfr const char *pstr = p + (q - p) + 1; 634178825Sdfr char *r; 635233294Sstas 636178825Sdfr r = malloc(pstr_len + 1); 637178825Sdfr if (r == NULL) { 638178825Sdfr der_free_oid(&oid); 639178825Sdfr ret = ENOMEM; 640178825Sdfr hx509_set_error_string(context, 0, ret, "out of memory"); 641178825Sdfr goto out; 642178825Sdfr } 643178825Sdfr memcpy(r, pstr, pstr_len); 644178825Sdfr r[pstr_len] = '\0'; 645178825Sdfr 646178825Sdfr ret = _hx509_name_modify(context, &n->der_name, 0, &oid, r); 647178825Sdfr free(r); 648178825Sdfr der_free_oid(&oid); 649178825Sdfr if(ret) 650178825Sdfr goto out; 651178825Sdfr } 652178825Sdfr p += len + last; 653178825Sdfr } 654178825Sdfr 655178825Sdfr *name = n; 656178825Sdfr 657178825Sdfr return 0; 658178825Sdfrout: 659178825Sdfr hx509_name_free(&n); 660178825Sdfr return HX509_NAME_MALFORMED; 661178825Sdfr} 662178825Sdfr 663178825Sdfr/** 664178825Sdfr * Copy a hx509 name object. 665178825Sdfr * 666178825Sdfr * @param context A hx509 cotext. 667178825Sdfr * @param from the name to copy from 668178825Sdfr * @param to the name to copy to 669178825Sdfr * 670178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 671178825Sdfr * 672178825Sdfr * @ingroup hx509_name 673178825Sdfr */ 674178825Sdfr 675178825Sdfrint 676178825Sdfrhx509_name_copy(hx509_context context, const hx509_name from, hx509_name *to) 677178825Sdfr{ 678178825Sdfr int ret; 679178825Sdfr 680178825Sdfr *to = calloc(1, sizeof(**to)); 681178825Sdfr if (*to == NULL) 682178825Sdfr return ENOMEM; 683178825Sdfr ret = copy_Name(&from->der_name, &(*to)->der_name); 684178825Sdfr if (ret) { 685178825Sdfr free(*to); 686178825Sdfr *to = NULL; 687178825Sdfr return ENOMEM; 688178825Sdfr } 689178825Sdfr return 0; 690178825Sdfr} 691178825Sdfr 692178825Sdfr/** 693178825Sdfr * Convert a hx509_name into a Name. 694178825Sdfr * 695178825Sdfr * @param from the name to copy from 696178825Sdfr * @param to the name to copy to 697178825Sdfr * 698178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 699178825Sdfr * 700178825Sdfr * @ingroup hx509_name 701178825Sdfr */ 702178825Sdfr 703178825Sdfrint 704178825Sdfrhx509_name_to_Name(const hx509_name from, Name *to) 705178825Sdfr{ 706178825Sdfr return copy_Name(&from->der_name, to); 707178825Sdfr} 708178825Sdfr 709178825Sdfrint 710178825Sdfrhx509_name_normalize(hx509_context context, hx509_name name) 711178825Sdfr{ 712178825Sdfr return 0; 713178825Sdfr} 714178825Sdfr 715178825Sdfr/** 716178825Sdfr * Expands variables in the name using env. Variables are on the form 717178825Sdfr * ${name}. Useful when dealing with certificate templates. 718178825Sdfr * 719178825Sdfr * @param context A hx509 cotext. 720178825Sdfr * @param name the name to expand. 721178825Sdfr * @param env environment variable to expand. 722178825Sdfr * 723178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 724178825Sdfr * 725178825Sdfr * @ingroup hx509_name 726178825Sdfr */ 727178825Sdfr 728178825Sdfrint 729178825Sdfrhx509_name_expand(hx509_context context, 730178825Sdfr hx509_name name, 731178825Sdfr hx509_env env) 732178825Sdfr{ 733178825Sdfr Name *n = &name->der_name; 734233294Sstas size_t i, j; 735178825Sdfr 736178825Sdfr if (env == NULL) 737178825Sdfr return 0; 738178825Sdfr 739178825Sdfr if (n->element != choice_Name_rdnSequence) { 740178825Sdfr hx509_set_error_string(context, 0, EINVAL, "RDN not of supported type"); 741178825Sdfr return EINVAL; 742178825Sdfr } 743178825Sdfr 744178825Sdfr for (i = 0 ; i < n->u.rdnSequence.len; i++) { 745178825Sdfr for (j = 0; j < n->u.rdnSequence.val[i].len; j++) { 746178825Sdfr /** Only UTF8String rdnSequence names are allowed */ 747178825Sdfr /* 748178825Sdfr THIS SHOULD REALLY BE: 749178825Sdfr COMP = n->u.rdnSequence.val[i].val[j]; 750178825Sdfr normalize COMP to utf8 751178825Sdfr check if there are variables 752178825Sdfr expand variables 753178825Sdfr convert back to orignal format, store in COMP 754178825Sdfr free normalized utf8 string 755178825Sdfr */ 756178825Sdfr DirectoryString *ds = &n->u.rdnSequence.val[i].val[j].value; 757178825Sdfr char *p, *p2; 758178825Sdfr struct rk_strpool *strpool = NULL; 759178825Sdfr 760178825Sdfr if (ds->element != choice_DirectoryString_utf8String) { 761178825Sdfr hx509_set_error_string(context, 0, EINVAL, "unsupported type"); 762178825Sdfr return EINVAL; 763178825Sdfr } 764178825Sdfr p = strstr(ds->u.utf8String, "${"); 765178825Sdfr if (p) { 766233294Sstas strpool = rk_strpoolprintf(strpool, "%.*s", 767233294Sstas (int)(p - ds->u.utf8String), 768178825Sdfr ds->u.utf8String); 769178825Sdfr if (strpool == NULL) { 770178825Sdfr hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 771178825Sdfr return ENOMEM; 772178825Sdfr } 773178825Sdfr } 774178825Sdfr while (p != NULL) { 775178825Sdfr /* expand variables */ 776178825Sdfr const char *value; 777178825Sdfr p2 = strchr(p, '}'); 778178825Sdfr if (p2 == NULL) { 779178825Sdfr hx509_set_error_string(context, 0, EINVAL, "missing }"); 780178825Sdfr rk_strpoolfree(strpool); 781178825Sdfr return EINVAL; 782178825Sdfr } 783178825Sdfr p += 2; 784178825Sdfr value = hx509_env_lfind(context, env, p, p2 - p); 785178825Sdfr if (value == NULL) { 786233294Sstas hx509_set_error_string(context, 0, EINVAL, 787178825Sdfr "variable %.*s missing", 788178825Sdfr (int)(p2 - p), p); 789178825Sdfr rk_strpoolfree(strpool); 790178825Sdfr return EINVAL; 791178825Sdfr } 792178825Sdfr strpool = rk_strpoolprintf(strpool, "%s", value); 793178825Sdfr if (strpool == NULL) { 794178825Sdfr hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 795178825Sdfr return ENOMEM; 796178825Sdfr } 797178825Sdfr p2++; 798178825Sdfr 799178825Sdfr p = strstr(p2, "${"); 800178825Sdfr if (p) 801233294Sstas strpool = rk_strpoolprintf(strpool, "%.*s", 802178825Sdfr (int)(p - p2), p2); 803178825Sdfr else 804178825Sdfr strpool = rk_strpoolprintf(strpool, "%s", p2); 805178825Sdfr if (strpool == NULL) { 806178825Sdfr hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 807178825Sdfr return ENOMEM; 808178825Sdfr } 809178825Sdfr } 810178825Sdfr if (strpool) { 811178825Sdfr free(ds->u.utf8String); 812178825Sdfr ds->u.utf8String = rk_strpoolcollect(strpool); 813178825Sdfr if (ds->u.utf8String == NULL) { 814178825Sdfr hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 815178825Sdfr return ENOMEM; 816178825Sdfr } 817178825Sdfr } 818178825Sdfr } 819178825Sdfr } 820178825Sdfr return 0; 821178825Sdfr} 822178825Sdfr 823178825Sdfr/** 824178825Sdfr * Free a hx509 name object, upond return *name will be NULL. 825178825Sdfr * 826178825Sdfr * @param name a hx509 name object to be freed. 827178825Sdfr * 828178825Sdfr * @ingroup hx509_name 829178825Sdfr */ 830178825Sdfr 831178825Sdfrvoid 832178825Sdfrhx509_name_free(hx509_name *name) 833178825Sdfr{ 834178825Sdfr free_Name(&(*name)->der_name); 835178825Sdfr memset(*name, 0, sizeof(**name)); 836178825Sdfr free(*name); 837178825Sdfr *name = NULL; 838178825Sdfr} 839178825Sdfr 840178825Sdfr/** 841178825Sdfr * Convert a DER encoded name info a string. 842178825Sdfr * 843178825Sdfr * @param data data to a DER/BER encoded name 844178825Sdfr * @param length length of data 845178825Sdfr * @param str the resulting string, is NULL on failure. 846178825Sdfr * 847178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 848178825Sdfr * 849178825Sdfr * @ingroup hx509_name 850178825Sdfr */ 851178825Sdfr 852178825Sdfrint 853178825Sdfrhx509_unparse_der_name(const void *data, size_t length, char **str) 854178825Sdfr{ 855178825Sdfr Name name; 856178825Sdfr int ret; 857178825Sdfr 858178825Sdfr *str = NULL; 859178825Sdfr 860178825Sdfr ret = decode_Name(data, length, &name, NULL); 861178825Sdfr if (ret) 862178825Sdfr return ret; 863178825Sdfr ret = _hx509_Name_to_string(&name, str); 864178825Sdfr free_Name(&name); 865178825Sdfr return ret; 866178825Sdfr} 867178825Sdfr 868178825Sdfr/** 869178825Sdfr * Convert a hx509_name object to DER encoded name. 870178825Sdfr * 871178825Sdfr * @param name name to concert 872178825Sdfr * @param os data to a DER encoded name, free the resulting octet 873178825Sdfr * string with hx509_xfree(os->data). 874178825Sdfr * 875178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 876178825Sdfr * 877178825Sdfr * @ingroup hx509_name 878178825Sdfr */ 879178825Sdfr 880178825Sdfrint 881178825Sdfrhx509_name_binary(const hx509_name name, heim_octet_string *os) 882178825Sdfr{ 883178825Sdfr size_t size; 884178825Sdfr int ret; 885178825Sdfr 886178825Sdfr ASN1_MALLOC_ENCODE(Name, os->data, os->length, &name->der_name, &size, ret); 887178825Sdfr if (ret) 888178825Sdfr return ret; 889178825Sdfr if (os->length != size) 890178825Sdfr _hx509_abort("internal ASN.1 encoder error"); 891178825Sdfr 892178825Sdfr return 0; 893178825Sdfr} 894178825Sdfr 895178825Sdfrint 896178825Sdfr_hx509_unparse_Name(const Name *aname, char **str) 897178825Sdfr{ 898178825Sdfr hx509_name name; 899178825Sdfr int ret; 900178825Sdfr 901178825Sdfr ret = _hx509_name_from_Name(aname, &name); 902178825Sdfr if (ret) 903178825Sdfr return ret; 904178825Sdfr 905178825Sdfr ret = hx509_name_to_string(name, str); 906178825Sdfr hx509_name_free(&name); 907178825Sdfr return ret; 908178825Sdfr} 909178825Sdfr 910178825Sdfr/** 911178825Sdfr * Unparse the hx509 name in name into a string. 912178825Sdfr * 913178825Sdfr * @param name the name to check if its empty/null. 914178825Sdfr * 915178825Sdfr * @return non zero if the name is empty/null. 916178825Sdfr * 917178825Sdfr * @ingroup hx509_name 918178825Sdfr */ 919178825Sdfr 920178825Sdfrint 921178825Sdfrhx509_name_is_null_p(const hx509_name name) 922178825Sdfr{ 923178825Sdfr return name->der_name.u.rdnSequence.len == 0; 924178825Sdfr} 925178825Sdfr 926178825Sdfr/** 927178825Sdfr * Unparse the hx509 name in name into a string. 928178825Sdfr * 929178825Sdfr * @param name the name to print 930178825Sdfr * @param str an allocated string returns the name in string form 931178825Sdfr * 932233294Sstas * @return An hx509 error code, see hx509_get_error_string(). 933178825Sdfr * 934178825Sdfr * @ingroup hx509_name 935178825Sdfr */ 936178825Sdfr 937178825Sdfrint 938178825Sdfrhx509_general_name_unparse(GeneralName *name, char **str) 939178825Sdfr{ 940178825Sdfr struct rk_strpool *strpool = NULL; 941178825Sdfr 942178825Sdfr *str = NULL; 943178825Sdfr 944178825Sdfr switch (name->element) { 945178825Sdfr case choice_GeneralName_otherName: { 946233294Sstas char *oid; 947233294Sstas hx509_oid_sprint(&name->u.otherName.type_id, &oid); 948233294Sstas if (oid == NULL) 949178825Sdfr return ENOMEM; 950233294Sstas strpool = rk_strpoolprintf(strpool, "otherName: %s", oid); 951233294Sstas free(oid); 952178825Sdfr break; 953178825Sdfr } 954178825Sdfr case choice_GeneralName_rfc822Name: 955233294Sstas strpool = rk_strpoolprintf(strpool, "rfc822Name: %.*s\n", 956233294Sstas (int)name->u.rfc822Name.length, 957233294Sstas (char *)name->u.rfc822Name.data); 958178825Sdfr break; 959178825Sdfr case choice_GeneralName_dNSName: 960233294Sstas strpool = rk_strpoolprintf(strpool, "dNSName: %.*s\n", 961233294Sstas (int)name->u.dNSName.length, 962233294Sstas (char *)name->u.dNSName.data); 963178825Sdfr break; 964178825Sdfr case choice_GeneralName_directoryName: { 965178825Sdfr Name dir; 966178825Sdfr char *s; 967178825Sdfr int ret; 968178825Sdfr memset(&dir, 0, sizeof(dir)); 969178825Sdfr dir.element = name->u.directoryName.element; 970178825Sdfr dir.u.rdnSequence = name->u.directoryName.u.rdnSequence; 971178825Sdfr ret = _hx509_unparse_Name(&dir, &s); 972178825Sdfr if (ret) 973178825Sdfr return ret; 974178825Sdfr strpool = rk_strpoolprintf(strpool, "directoryName: %s", s); 975178825Sdfr free(s); 976178825Sdfr break; 977178825Sdfr } 978178825Sdfr case choice_GeneralName_uniformResourceIdentifier: 979233294Sstas strpool = rk_strpoolprintf(strpool, "URI: %.*s", 980233294Sstas (int)name->u.uniformResourceIdentifier.length, 981233294Sstas (char *)name->u.uniformResourceIdentifier.data); 982178825Sdfr break; 983178825Sdfr case choice_GeneralName_iPAddress: { 984178825Sdfr unsigned char *a = name->u.iPAddress.data; 985178825Sdfr 986178825Sdfr strpool = rk_strpoolprintf(strpool, "IPAddress: "); 987178825Sdfr if (strpool == NULL) 988178825Sdfr break; 989178825Sdfr if (name->u.iPAddress.length == 4) 990233294Sstas strpool = rk_strpoolprintf(strpool, "%d.%d.%d.%d", 991178825Sdfr a[0], a[1], a[2], a[3]); 992178825Sdfr else if (name->u.iPAddress.length == 16) 993233294Sstas strpool = rk_strpoolprintf(strpool, 994178825Sdfr "%02X:%02X:%02X:%02X:" 995178825Sdfr "%02X:%02X:%02X:%02X:" 996178825Sdfr "%02X:%02X:%02X:%02X:" 997233294Sstas "%02X:%02X:%02X:%02X", 998178825Sdfr a[0], a[1], a[2], a[3], 999178825Sdfr a[4], a[5], a[6], a[7], 1000178825Sdfr a[8], a[9], a[10], a[11], 1001178825Sdfr a[12], a[13], a[14], a[15]); 1002178825Sdfr else 1003233294Sstas strpool = rk_strpoolprintf(strpool, 1004178825Sdfr "unknown IP address of length %lu", 1005178825Sdfr (unsigned long)name->u.iPAddress.length); 1006178825Sdfr break; 1007178825Sdfr } 1008178825Sdfr case choice_GeneralName_registeredID: { 1009233294Sstas char *oid; 1010233294Sstas hx509_oid_sprint(&name->u.registeredID, &oid); 1011233294Sstas if (oid == NULL) 1012178825Sdfr return ENOMEM; 1013233294Sstas strpool = rk_strpoolprintf(strpool, "registeredID: %s", oid); 1014233294Sstas free(oid); 1015178825Sdfr break; 1016178825Sdfr } 1017178825Sdfr default: 1018178825Sdfr return EINVAL; 1019178825Sdfr } 1020178825Sdfr if (strpool == NULL) 1021178825Sdfr return ENOMEM; 1022178825Sdfr 1023178825Sdfr *str = rk_strpoolcollect(strpool); 1024178825Sdfr 1025178825Sdfr return 0; 1026178825Sdfr} 1027