LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/hx509 - name.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 150 819 18.3 %
Date: 2024-04-21 15:09:00 Functions: 12 32 37.5 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2004 - 2009 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  *
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer.
      12             :  *
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  *
      17             :  * 3. Neither the name of the Institute nor the names of its contributors
      18             :  *    may be used to endorse or promote products derived from this software
      19             :  *    without specific prior written permission.
      20             :  *
      21             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      22             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      23             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      24             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      25             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      26             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      27             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      29             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      30             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      31             :  * SUCH DAMAGE.
      32             :  */
      33             : 
      34             : #include "hx_locl.h"
      35             : #include <wind.h>
      36             : #include "char_map.h"
      37             : 
      38             : /**
      39             :  * @page page_name PKIX/X.509 Names
      40             :  *
      41             :  * There are several names in PKIX/X.509, GeneralName and Name.
      42             :  *
      43             :  * A Name consists of an ordered list of Relative Distinguished Names
      44             :  * (RDN). Each RDN consists of an unordered list of typed strings. The
      45             :  * types are defined by OID and have long and short description. For
      46             :  * example id-at-commonName (2.5.4.3) have the long name CommonName
      47             :  * and short name CN. The string itself can be of several encoding,
      48             :  * UTF8, UTF16, Teltex string, etc. The type limit what encoding
      49             :  * should be used.
      50             :  *
      51             :  * GeneralName is a broader nametype that can contains al kind of
      52             :  * stuff like Name, IP addresses, partial Name, etc.
      53             :  *
      54             :  * Name is mapped into a hx509_name object.
      55             :  *
      56             :  * Parse and string name into a hx509_name object with hx509_parse_name(),
      57             :  * make it back into string representation with hx509_name_to_string().
      58             :  *
      59             :  * Name string are defined rfc2253, rfc1779 and X.501.
      60             :  *
      61             :  * See the library functions here: @ref hx509_name
      62             :  */
      63             : 
      64             : static const struct {
      65             :     const char *n;
      66             :     const heim_oid *o;
      67             :     int type_choice; /* Preference for DirectoryString choice; 0 -> no pref */
      68             :     wind_profile_flags flags;
      69             :     /*
      70             :      * RFC52380 imposes maximum lengths for some strings in Names.  These are
      71             :      * ASN.1 size limits.  We should implement these in our copy of the PKIX
      72             :      * ASN.1 module.  For now we treat them as maximum byte counts rather than
      73             :      * maximum character counts, and we encode and enforce them here.
      74             :      *
      75             :      * 0 -> no max
      76             :      *
      77             :      * Some of these attributes aren't of type DirectoryString, so our
      78             :      * type_choice isn't really correct.  We're not really set up for
      79             :      * attributes whose types aren't DirectoryString or one of its choice arms'
      80             :      * type, much less are we set up for non-string attribute value types.
      81             :      */
      82             :     size_t max_bytes;
      83             : } no[] = {
      84             :     { "C", &asn1_oid_id_at_countryName,
      85             :         choice_DirectoryString_printableString, 0, 2 },
      86             :     { "CN", &asn1_oid_id_at_commonName, 0, 0, ub_common_name },
      87             :     { "DC", &asn1_oid_id_domainComponent, choice_DirectoryString_ia5String,
      88             :         0, 63 }, /* DNS label */
      89             :     { "L", &asn1_oid_id_at_localityName, 0, 0, ub_locality_name },
      90             :     { "O", &asn1_oid_id_at_organizationName, 0, 0, ub_organization_name },
      91             :     { "OU", &asn1_oid_id_at_organizationalUnitName, 0, 0,
      92             :         ub_organizational_unit_name },
      93             :     { "S", &asn1_oid_id_at_stateOrProvinceName, 0, 0, ub_state_name },
      94             :     { "STREET", &asn1_oid_id_at_streetAddress, 0, 0, 0 }, /* ENOTSUP */
      95             :     { "UID", &asn1_oid_id_Userid, 0, 0, ub_numeric_user_id_length },
      96             :     { "emailAddress", &asn1_oid_id_pkcs9_emailAddress,
      97             :         choice_DirectoryString_ia5String, 0, ub_emailaddress_length },
      98             :     /* This is for DevID certificates and maybe others */
      99             :     { "serialNumber", &asn1_oid_id_at_serialNumber, 0, 0, ub_serial_number },
     100             :     /* These are for TPM 2.0 Endorsement Key Certificates (EKCerts) */
     101             :     { "TPMManufacturer", &asn1_oid_tcg_at_tpmManufacturer, 0, 0,
     102             :         ub_emailaddress_length },
     103             :     { "TPMModel", &asn1_oid_tcg_at_tpmModel, 0, 0, ub_emailaddress_length },
     104             :     { "TPMVersion", &asn1_oid_tcg_at_tpmVersion, 0, 0, ub_emailaddress_length },
     105             : };
     106             : 
     107             : static char *
     108         640 : quote_string(const char *f, size_t len, int flags, size_t *rlen)
     109             : {
     110           0 :     size_t i, j, tolen;
     111         640 :     const unsigned char *from = (const unsigned char *)f;
     112           0 :     unsigned char *to;
     113             : 
     114         640 :     tolen = len * 3 + 1;
     115         640 :     to = malloc(tolen);
     116         640 :     if (to == NULL)
     117           0 :         return NULL;
     118             : 
     119       12701 :     for (i = 0, j = 0; i < len; i++) {
     120       12061 :         unsigned char map = char_map[from[i]] & flags;
     121       12061 :         if (i == 0 && (map & Q_RFC2253_QUOTE_FIRST)) {
     122           0 :             to[j++] = '\\';
     123           0 :             to[j++] = from[i];
     124       12061 :         } else if ((i + 1) == len && (map & Q_RFC2253_QUOTE_LAST)) {
     125             : 
     126           0 :             to[j++] = '\\';
     127           0 :             to[j++] = from[i];
     128       12061 :         } else if (map & Q_RFC2253_QUOTE) {
     129          32 :             to[j++] = '\\';
     130          32 :             to[j++] = from[i];
     131       12029 :         } else if (map & Q_RFC2253_HEX) {
     132           0 :             int l = snprintf((char *)&to[j], tolen - j - 1,
     133           0 :                              "#%02x", (unsigned char)from[i]);
     134           0 :             j += l;
     135             :         } else {
     136       12029 :             to[j++] = from[i];
     137             :         }
     138             :     }
     139         640 :     to[j] = '\0';
     140         640 :     assert(j < tolen);
     141         640 :     *rlen = j;
     142         640 :     return (char *)to;
     143             : }
     144             : 
     145             : 
     146             : static int
     147        2448 : append_string(char **str, size_t *total_len, const char *ss,
     148             :               size_t len, int quote)
     149             : {
     150           0 :     char *s, *qs;
     151             : 
     152        2448 :     if (quote)
     153         640 :         qs = quote_string(ss, len, Q_RFC2253, &len);
     154             :     else
     155        1808 :         qs = rk_UNCONST(ss);
     156             : 
     157        2448 :     s = realloc(*str, len + *total_len + 1);
     158        2448 :     if (s == NULL)
     159           0 :         _hx509_abort("allocation failure"); /* XXX */
     160        2448 :     memcpy(s + *total_len, qs, len);
     161        2448 :     if (qs != ss)
     162         640 :         free(qs);
     163        2448 :     s[*total_len + len] = '\0';
     164        2448 :     *str = s;
     165        2448 :     *total_len += len;
     166        2448 :     return 0;
     167             : }
     168             : 
     169             : static char *
     170         640 : oidtostring(const heim_oid *type, int *type_choice)
     171             : {
     172           0 :     char *s;
     173           0 :     size_t i;
     174             : 
     175         640 :     if (type_choice)
     176           0 :         *type_choice = choice_DirectoryString_utf8String;
     177             : 
     178        3152 :     for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) {
     179        3152 :         if (der_heim_oid_cmp(no[i].o, type) == 0) {
     180         640 :             if (type_choice && no[i].type_choice)
     181           0 :                 *type_choice = no[i].type_choice;
     182         640 :             return strdup(no[i].n);
     183             :         }
     184             :     }
     185           0 :     if (der_print_heim_oid(type, '.', &s) != 0)
     186           0 :         return NULL;
     187           0 :     return s;
     188             : }
     189             : 
     190             : static size_t
     191           0 : oidtomaxlen(const heim_oid *type)
     192             : {
     193           0 :     size_t i;
     194             : 
     195           0 :     for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) {
     196           0 :         if (der_heim_oid_cmp(no[i].o, type) == 0)
     197           0 :             return no[i].max_bytes;
     198             :     }
     199           0 :     return 0;
     200             : }
     201             : 
     202             : static int
     203           0 : stringtooid(const char *name, size_t len, heim_oid *oid)
     204             : {
     205           0 :     int ret;
     206           0 :     size_t i;
     207           0 :     char *s;
     208             : 
     209           0 :     memset(oid, 0, sizeof(*oid));
     210             : 
     211           0 :     for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) {
     212           0 :         if (strncasecmp(no[i].n, name, len) == 0)
     213           0 :             return der_copy_oid(no[i].o, oid);
     214             :     }
     215           0 :     s = malloc(len + 1);
     216           0 :     if (s == NULL)
     217           0 :         return ENOMEM;
     218           0 :     memcpy(s, name, len);
     219           0 :     s[len] = '\0';
     220           0 :     ret = der_parse_heim_oid(s, ".", oid);
     221           0 :     free(s);
     222           0 :     return ret;
     223             : }
     224             : 
     225             : /**
     226             :  * Convert the hx509 name object into a printable string.
     227             :  * The resulting string should be freed with free().
     228             :  *
     229             :  * @param name name to print
     230             :  * @param str the string to return
     231             :  *
     232             :  * @return An hx509 error code, see hx509_get_error_string().
     233             :  *
     234             :  * @ingroup hx509_name
     235             :  */
     236             : 
     237             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     238         112 : hx509_name_to_string(const hx509_name name, char **str)
     239             : {
     240         112 :     return _hx509_Name_to_string(&name->der_name, str);
     241             : }
     242             : 
     243             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     244         112 : _hx509_Name_to_string(const Name *n, char **str)
     245             : {
     246         112 :     size_t total_len = 0;
     247           0 :     size_t i, j, m;
     248           0 :     int ret;
     249             : 
     250         112 :     *str = strdup("");
     251         112 :     if (*str == NULL)
     252           0 :         return ENOMEM;
     253             : 
     254         752 :     for (m = n->u.rdnSequence.len; m > 0; m--) {
     255           0 :         size_t len;
     256         640 :         i = m - 1;
     257             : 
     258        1280 :         for (j = 0; j < n->u.rdnSequence.val[i].len; j++) {
     259         640 :             DirectoryString *ds = &n->u.rdnSequence.val[i].val[j].value;
     260           0 :             char *oidname;
     261           0 :             char *ss;
     262             : 
     263         640 :             oidname = oidtostring(&n->u.rdnSequence.val[i].val[j].type, NULL);
     264             : 
     265         640 :             switch(ds->element) {
     266          80 :             case choice_DirectoryString_ia5String:
     267          80 :                 ss = ds->u.ia5String.data;
     268          80 :                 len = ds->u.ia5String.length;
     269          80 :                 break;
     270         112 :             case choice_DirectoryString_printableString:
     271         112 :                 ss = ds->u.printableString.data;
     272         112 :                 len = ds->u.printableString.length;
     273         112 :                 break;
     274         448 :             case choice_DirectoryString_utf8String:
     275         448 :                 ss = ds->u.utf8String;
     276         448 :                 len = strlen(ss);
     277         448 :                 break;
     278           0 :             case choice_DirectoryString_bmpString: {
     279           0 :                 const uint16_t *bmp = ds->u.bmpString.data;
     280           0 :                 size_t bmplen = ds->u.bmpString.length;
     281           0 :                 size_t k;
     282             : 
     283           0 :                 ret = wind_ucs2utf8_length(bmp, bmplen, &k);
     284           0 :                 if (ret) {
     285           0 :                     free(oidname);
     286           0 :                     free(*str);
     287           0 :                     *str = NULL;
     288           0 :                     return ret;
     289             :                 }
     290             : 
     291           0 :                 ss = malloc(k + 1);
     292           0 :                 if (ss == NULL)
     293           0 :                     _hx509_abort("allocation failure"); /* XXX */
     294           0 :                 ret = wind_ucs2utf8(bmp, bmplen, ss, NULL);
     295           0 :                 if (ret) {
     296           0 :                     free(oidname);
     297           0 :                     free(ss);
     298           0 :                     free(*str);
     299           0 :                     *str = NULL;
     300           0 :                     return ret;
     301             :                 }
     302           0 :                 ss[k] = '\0';
     303           0 :                 len = k;
     304           0 :                 break;
     305             :             }
     306           0 :             case choice_DirectoryString_teletexString:
     307           0 :                 ss = ds->u.teletexString;
     308           0 :                 len = strlen(ss);
     309           0 :                 break;
     310           0 :             case choice_DirectoryString_universalString: {
     311           0 :                 const uint32_t *uni = ds->u.universalString.data;
     312           0 :                 size_t unilen = ds->u.universalString.length;
     313           0 :                 size_t k;
     314             : 
     315           0 :                 ret = wind_ucs4utf8_length(uni, unilen, &k);
     316           0 :                 if (ret) {
     317           0 :                     free(oidname);
     318           0 :                     free(*str);
     319           0 :                     *str = NULL;
     320           0 :                     return ret;
     321             :                 }
     322             : 
     323           0 :                 ss = malloc(k + 1);
     324           0 :                 if (ss == NULL)
     325           0 :                     _hx509_abort("allocation failure"); /* XXX */
     326           0 :                 ret = wind_ucs4utf8(uni, unilen, ss, NULL);
     327           0 :                 if (ret) {
     328           0 :                     free(ss);
     329           0 :                     free(oidname);
     330           0 :                     free(*str);
     331           0 :                     *str = NULL;
     332           0 :                     return ret;
     333             :                 }
     334           0 :                 ss[k] = '\0';
     335           0 :                 len = k;
     336           0 :                 break;
     337             :             }
     338           0 :             default:
     339           0 :                 _hx509_abort("unknown directory type: %d", ds->element);
     340             :                 exit(1);
     341             :             }
     342         640 :             append_string(str, &total_len, oidname, strlen(oidname), 0);
     343         640 :             free(oidname);
     344         640 :             append_string(str, &total_len, "=", 1, 0);
     345         640 :             append_string(str, &total_len, ss, len, 1);
     346         640 :             if (ds->element == choice_DirectoryString_bmpString ||
     347         640 :                 ds->element == choice_DirectoryString_universalString)
     348             :             {
     349           0 :                 free(ss);
     350             :             }
     351         640 :             if (j + 1 < n->u.rdnSequence.val[i].len)
     352           0 :                 append_string(str, &total_len, "+", 1, 0);
     353             :         }
     354             : 
     355         640 :         if (i > 0)
     356         528 :             append_string(str, &total_len, ",", 1, 0);
     357             :     }
     358         112 :     return 0;
     359             : }
     360             : 
     361             : #define COPYCHARARRAY(_ds,_el,_l,_n)                    \
     362             :         (_l) = strlen(_ds->u._el);                   \
     363             :         (_n) = malloc((_l + 1) * sizeof((_n)[0]));      \
     364             :         if ((_n) == NULL)                               \
     365             :             return ENOMEM;                              \
     366             :         for (i = 0; i < (_l); i++)                   \
     367             :             (_n)[i] = _ds->u._el[i]
     368             : 
     369             : 
     370             : #define COPYVALARRAY(_ds,_el,_l,_n)                     \
     371             :         (_l) = _ds->u._el.length;                    \
     372             :         (_n) = malloc((_l + 1) * sizeof((_n)[0]));      \
     373             :         if ((_n) == NULL)                               \
     374             :             return ENOMEM;                              \
     375             :         for (i = 0; i < (_l); i++)                   \
     376             :             (_n)[i] = _ds->u._el.data[i]
     377             : 
     378             : #define COPYVOIDARRAY(_ds,_el,_l,_n)                    \
     379             :         (_l) = _ds->u._el.length;                    \
     380             :         (_n) = malloc((_l + 1) * sizeof((_n)[0]));      \
     381             :         if ((_n) == NULL)                               \
     382             :             return ENOMEM;                              \
     383             :         for (i = 0; i < (_l); i++)                   \
     384             :             (_n)[i] = ((unsigned char *)_ds->u._el.data)[i]
     385             : 
     386             : 
     387             : 
     388             : static int
     389        3934 : dsstringprep(const DirectoryString *ds, uint32_t **rname, size_t *rlen)
     390             : {
     391           0 :     wind_profile_flags flags;
     392           0 :     size_t i, len;
     393        3934 :     int ret = 0;
     394           0 :     uint32_t *name;
     395             : 
     396        3934 :     *rname = NULL;
     397        3934 :     *rlen = 0;
     398             : 
     399        3934 :     switch(ds->element) {
     400         562 :     case choice_DirectoryString_ia5String:
     401         562 :         flags = WIND_PROFILE_LDAP;
     402       21918 :         COPYVOIDARRAY(ds, ia5String, len, name);
     403         562 :         break;
     404         562 :     case choice_DirectoryString_printableString:
     405         562 :         flags = WIND_PROFILE_LDAP;
     406         562 :         flags |= WIND_PROFILE_LDAP_CASE_EXACT_ATTRIBUTE;
     407        1686 :         COPYVOIDARRAY(ds, printableString, len, name);
     408         562 :         break;
     409           0 :     case choice_DirectoryString_teletexString:
     410           0 :         flags = WIND_PROFILE_LDAP_CASE;
     411           0 :         COPYCHARARRAY(ds, teletexString, len, name);
     412           0 :         break;
     413           0 :     case choice_DirectoryString_bmpString:
     414           0 :         flags = WIND_PROFILE_LDAP;
     415           0 :         COPYVALARRAY(ds, bmpString, len, name);
     416           0 :         break;
     417           0 :     case choice_DirectoryString_universalString:
     418           0 :         flags = WIND_PROFILE_LDAP;
     419           0 :         COPYVALARRAY(ds, universalString, len, name);
     420           0 :         break;
     421        2810 :     case choice_DirectoryString_utf8String:
     422        2810 :         flags = WIND_PROFILE_LDAP;
     423        2810 :         ret = wind_utf8ucs4_length(ds->u.utf8String, &len);
     424        2810 :         if (ret)
     425           0 :             return ret;
     426        2810 :         name = malloc((len + 1) * sizeof(name[0]));
     427        2810 :         if (name == NULL)
     428           0 :             return ENOMEM;
     429        2810 :         ret = wind_utf8ucs4(ds->u.utf8String, name, &len);
     430        2810 :         if (ret) {
     431           0 :             free(name);
     432           0 :             return ret;
     433             :         }
     434        2810 :         break;
     435           0 :     default:
     436           0 :         _hx509_abort("unknown directory type: %d", ds->element);
     437             :     }
     438             : 
     439        3934 :     *rlen = len;
     440             :     /* try a couple of times to get the length right, XXX gross */
     441        3934 :     for (i = 0; i < 4; i++) {
     442        3934 :         *rlen = *rlen * 2;
     443        3934 :         if ((*rname = malloc((rlen[0] + 1) * sizeof((*rname)[0]))) == NULL) {
     444           0 :             ret = ENOMEM;
     445           0 :             break;
     446             :         }
     447             : 
     448        3934 :         ret = wind_stringprep(name, len, *rname, rlen, flags);
     449        3934 :         if (ret == WIND_ERR_OVERRUN) {
     450           0 :             free(*rname);
     451           0 :             *rname = NULL;
     452           0 :             continue;
     453             :         } else
     454        3934 :             break;
     455             :     }
     456        3934 :     free(name);
     457        3934 :     if (ret) {
     458           0 :         if (*rname)
     459           0 :             free(*rname);
     460           0 :         *rname = NULL;
     461           0 :         *rlen = 0;
     462           0 :         return ret;
     463             :     }
     464             : 
     465        3934 :     return 0;
     466             : }
     467             : 
     468             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     469        1967 : _hx509_name_ds_cmp(const DirectoryString *ds1,
     470             :                    const DirectoryString *ds2,
     471             :                    int *diff)
     472             : {
     473           0 :     uint32_t *ds1lp, *ds2lp;
     474           0 :     size_t ds1len, ds2len, i;
     475           0 :     int ret;
     476             : 
     477        1967 :     ret = dsstringprep(ds1, &ds1lp, &ds1len);
     478        1967 :     if (ret)
     479           0 :         return ret;
     480        1967 :     ret = dsstringprep(ds2, &ds2lp, &ds2len);
     481        1967 :     if (ret) {
     482           0 :         free(ds1lp);
     483           0 :         return ret;
     484             :     }
     485             : 
     486        1967 :     if (ds1len != ds2len)
     487           0 :         *diff = ds1len - ds2len;
     488             :     else {
     489       34844 :         for (i = 0; i < ds1len; i++) {
     490       32877 :             *diff = ds1lp[i] - ds2lp[i];
     491       32877 :             if (*diff)
     492           0 :                 break;
     493             :         }
     494             :     }
     495        1967 :     free(ds1lp);
     496        1967 :     free(ds2lp);
     497             : 
     498        1967 :     return 0;
     499             : }
     500             : 
     501             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     502         449 : _hx509_name_cmp(const Name *n1, const Name *n2, int *c)
     503             : {
     504           0 :     int ret;
     505           0 :     size_t i, j;
     506             : 
     507         449 :     *c = n1->u.rdnSequence.len - n2->u.rdnSequence.len;
     508         449 :     if (*c)
     509         168 :         return 0;
     510             : 
     511        2248 :     for (i = 0 ; i < n1->u.rdnSequence.len; i++) {
     512        1967 :         *c = n1->u.rdnSequence.val[i].len - n2->u.rdnSequence.val[i].len;
     513        1967 :         if (*c)
     514           0 :             return 0;
     515             : 
     516        3934 :         for (j = 0; j < n1->u.rdnSequence.val[i].len; j++) {
     517        3934 :             *c = der_heim_oid_cmp(&n1->u.rdnSequence.val[i].val[j].type,
     518        1967 :                                   &n1->u.rdnSequence.val[i].val[j].type);
     519        1967 :             if (*c)
     520           0 :                 return 0;
     521             : 
     522        1967 :             ret = _hx509_name_ds_cmp(&n1->u.rdnSequence.val[i].val[j].value,
     523        1967 :                                      &n2->u.rdnSequence.val[i].val[j].value,
     524             :                                      c);
     525        1967 :             if (ret)
     526           0 :                 return ret;
     527        1967 :             if (*c)
     528           0 :                 return 0;
     529             :         }
     530             :     }
     531         281 :     *c = 0;
     532         281 :     return 0;
     533             : }
     534             : 
     535             : /**
     536             :  * Compare to hx509 name object, useful for sorting.
     537             :  *
     538             :  * @param n1 a hx509 name object.
     539             :  * @param n2 a hx509 name object.
     540             :  *
     541             :  * @return 0 the objects are the same, returns > 0 is n2 is "larger"
     542             :  * then n2, < 0 if n1 is "smaller" then n2.
     543             :  *
     544             :  * @ingroup hx509_name
     545             :  */
     546             : 
     547             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     548           0 : hx509_name_cmp(hx509_name n1, hx509_name n2)
     549             : {
     550           0 :     int ret, diff;
     551           0 :     ret = _hx509_name_cmp(&n1->der_name, &n2->der_name, &diff);
     552           0 :     if (ret)
     553           0 :         return ret;
     554           0 :     return diff;
     555             : }
     556             : 
     557             : 
     558             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     559         354 : _hx509_name_from_Name(const Name *n, hx509_name *name)
     560             : {
     561           0 :     int ret;
     562         354 :     *name = calloc(1, sizeof(**name));
     563         354 :     if (*name == NULL)
     564           0 :         return ENOMEM;
     565         354 :     ret = copy_Name(n, &(*name)->der_name);
     566         354 :     if (ret) {
     567           0 :         free(*name);
     568           0 :         *name = NULL;
     569             :     }
     570         354 :     return ret;
     571             : }
     572             : 
     573             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     574           0 : _hx509_name_modify(hx509_context context,
     575             :                    Name *name,
     576             :                    int append,
     577             :                    const heim_oid *oid,
     578             :                    const char *str)
     579             : {
     580           0 :     RelativeDistinguishedName rdn;
     581           0 :     size_t max_len = oidtomaxlen(oid);
     582           0 :     char *s = NULL;
     583           0 :     int type_choice = choice_DirectoryString_printableString;
     584           0 :     int ret;
     585             : 
     586             :     /*
     587             :      * Check string length upper bounds.
     588             :      *
     589             :      * Because we don't have these bounds in our copy of the PKIX ASN.1 module,
     590             :      * and because we might like to catch these early anyways, we enforce them
     591             :      * here.
     592             :      */
     593           0 :     if (max_len && strlen(str) > max_len) {
     594           0 :         char *a = oidtostring(oid, &type_choice);
     595             : 
     596           0 :         ret = HX509_PARSING_NAME_FAILED;
     597           0 :         hx509_set_error_string(context, 0, ret, "RDN attribute %s value too "
     598             :                                "long (max %llu): %s", a ? a : "<unknown>",
     599             :                                max_len, str);
     600           0 :         free(a);
     601           0 :         return ret;
     602             :     }
     603             : 
     604           0 :     memset(&rdn, 0, sizeof(rdn));
     605           0 :     if ((rdn.val = malloc(sizeof(rdn.val[0]))) == NULL) {
     606           0 :         hx509_set_error_string(context, 0, ENOMEM, "Out of memory");
     607           0 :         return ENOMEM;
     608             :     }
     609           0 :     rdn.len = 1;
     610             : 
     611             :     /*
     612             :      * How best to pick a type for this attribute value?
     613             :      *
     614             :      * Options:
     615             :      *
     616             :      * 1) the API deals only in UTF-8, let the callers convert to/from UTF-8
     617             :      *    and whatever the current locale wants
     618             :      *
     619             :      * 2) use the best type for the codeset of the current locale.
     620             :      *
     621             :      * We choose (1).
     622             :      *
     623             :      * However, for some cases we really should prefer other types when the
     624             :      * input string is all printable ASCII.
     625             :      */
     626           0 :     rdn.val[0].value.element = type_choice;
     627           0 :     if ((s = strdup(str)) == NULL ||
     628           0 :         der_copy_oid(oid, &rdn.val[0].type)) {
     629           0 :         free(rdn.val);
     630           0 :         free(s);
     631           0 :         return hx509_enomem(context);
     632             :     }
     633           0 :     switch (rdn.val[0].value.element) {
     634             :     /* C strings: */
     635           0 :     case choice_DirectoryString_utf8String:
     636           0 :         rdn.val[0].value.u.utf8String = s;
     637           0 :         break;
     638           0 :     case choice_DirectoryString_teletexString:
     639           0 :         rdn.val[0].value.u.teletexString = s;
     640           0 :         break;
     641             : 
     642             :     /* Length and pointer */
     643           0 :     case choice_DirectoryString_ia5String:
     644           0 :         rdn.val[0].value.u.ia5String.data = s;
     645           0 :         rdn.val[0].value.u.ia5String.length = strlen(s);
     646           0 :         break;
     647           0 :     case choice_DirectoryString_printableString:
     648           0 :         rdn.val[0].value.u.printableString.data = s;
     649           0 :         rdn.val[0].value.u.printableString.length = strlen(s);
     650           0 :         break;
     651           0 :     case choice_DirectoryString_universalString:
     652           0 :         free(s);
     653           0 :         free(rdn.val);
     654           0 :         hx509_set_error_string(context, 0, ENOTSUP, "UniversalString not supported");
     655           0 :         return ENOTSUP;
     656           0 :     case choice_DirectoryString_bmpString:
     657           0 :         free(s);
     658           0 :         free(rdn.val);
     659           0 :         hx509_set_error_string(context, 0, ENOTSUP, "BMPString not supported");
     660           0 :         return ENOTSUP;
     661           0 :     default:
     662           0 :         free(s);
     663           0 :         free(rdn.val);
     664           0 :         hx509_set_error_string(context, 0, ENOTSUP,
     665             :                                "Internal error; unknown DirectoryString choice");
     666           0 :         return ENOTSUP;
     667             :     }
     668             : 
     669             :     /* Append RDN.  If the caller wanted to prepend instead, we'll rotate. */
     670           0 :     ret = add_RDNSequence(&name->u.rdnSequence, &rdn);
     671           0 :     free_RelativeDistinguishedName(&rdn);
     672             : 
     673           0 :     if (ret || append || name->u.rdnSequence.len < 2)
     674           0 :         return ret;
     675             : 
     676             :     /* Rotate */
     677           0 :     rdn = name->u.rdnSequence.val[name->u.rdnSequence.len - 1];
     678           0 :     memmove(&name->u.rdnSequence.val[1],
     679           0 :             &name->u.rdnSequence.val[0],
     680           0 :             (name->u.rdnSequence.len - 1) *
     681             :             sizeof(name->u.rdnSequence.val[0]));
     682           0 :     name->u.rdnSequence.val[0] = rdn;
     683           0 :     return 0;
     684             : }
     685             : 
     686             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     687           0 : hx509_empty_name(hx509_context context, hx509_name *name)
     688             : {
     689           0 :     if ((*name = calloc(1, sizeof(**name))) == NULL) {
     690           0 :         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
     691           0 :         return ENOMEM;
     692             :     }
     693           0 :     (*name)->der_name.element = choice_Name_rdnSequence;
     694           0 :     (*name)->der_name.u.rdnSequence.val = 0;
     695           0 :     (*name)->der_name.u.rdnSequence.len = 0;
     696           0 :     return 0;
     697             : }
     698             : 
     699             : /**
     700             :  * Parse a string into a hx509 name object.
     701             :  *
     702             :  * @param context A hx509 context.
     703             :  * @param str a string to parse.
     704             :  * @param name the resulting object, NULL in case of error.
     705             :  *
     706             :  * @return An hx509 error code, see hx509_get_error_string().
     707             :  *
     708             :  * @ingroup hx509_name
     709             :  */
     710             : 
     711             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     712           0 : hx509_parse_name(hx509_context context, const char *str, hx509_name *name)
     713             : {
     714           0 :     const char *p, *q;
     715           0 :     size_t len;
     716           0 :     hx509_name n;
     717           0 :     int ret;
     718             : 
     719           0 :     *name = NULL;
     720             : 
     721           0 :     n = calloc(1, sizeof(*n));
     722           0 :     if (n == NULL) {
     723           0 :         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
     724           0 :         return ENOMEM;
     725             :     }
     726             : 
     727           0 :     n->der_name.element = choice_Name_rdnSequence;
     728             : 
     729           0 :     p = str;
     730             : 
     731           0 :     while (p != NULL && *p != '\0') {
     732           0 :         heim_oid oid;
     733           0 :         int last;
     734             : 
     735           0 :         q = strchr(p, ',');
     736           0 :         if (q) {
     737           0 :             len = (q - p);
     738           0 :             last = 1;
     739             :         } else {
     740           0 :             len = strlen(p);
     741           0 :             last = 0;
     742             :         }
     743             : 
     744           0 :         q = strchr(p, '=');
     745           0 :         if (q == NULL) {
     746           0 :             ret = HX509_PARSING_NAME_FAILED;
     747           0 :             hx509_set_error_string(context, 0, ret, "missing = in %s", p);
     748           0 :             goto out;
     749             :         }
     750           0 :         if (q == p) {
     751           0 :             ret = HX509_PARSING_NAME_FAILED;
     752           0 :             hx509_set_error_string(context, 0, ret,
     753             :                                    "missing name before = in %s", p);
     754           0 :             goto out;
     755             :         }
     756             : 
     757           0 :         if ((size_t)(q - p) > len) {
     758           0 :             ret = HX509_PARSING_NAME_FAILED;
     759           0 :             hx509_set_error_string(context, 0, ret, " = after , in %s", p);
     760           0 :             goto out;
     761             :         }
     762             : 
     763           0 :         ret = stringtooid(p, q - p, &oid);
     764           0 :         if (ret) {
     765           0 :             ret = HX509_PARSING_NAME_FAILED;
     766           0 :             hx509_set_error_string(context, 0, ret,
     767           0 :                                    "unknown type: %.*s", (int)(q - p), p);
     768           0 :             goto out;
     769             :         }
     770             : 
     771             :         {
     772           0 :             size_t pstr_len = len - (q - p) - 1;
     773           0 :             const char *pstr = p + (q - p) + 1;
     774           0 :             char *r;
     775             : 
     776           0 :             r = malloc(pstr_len + 1);
     777           0 :             if (r == NULL) {
     778           0 :                 der_free_oid(&oid);
     779           0 :                 ret = ENOMEM;
     780           0 :                 hx509_set_error_string(context, 0, ret, "out of memory");
     781           0 :                 goto out;
     782             :             }
     783           0 :             memcpy(r, pstr, pstr_len);
     784           0 :             r[pstr_len] = '\0';
     785             : 
     786           0 :             ret = _hx509_name_modify(context, &n->der_name, 0, &oid, r);
     787           0 :             free(r);
     788           0 :             der_free_oid(&oid);
     789           0 :             if(ret)
     790           0 :                 goto out;
     791             :         }
     792           0 :         p += len + last;
     793             :     }
     794             : 
     795           0 :     *name = n;
     796             : 
     797           0 :     return 0;
     798           0 : out:
     799           0 :     hx509_name_free(&n);
     800           0 :     return HX509_NAME_MALFORMED;
     801             : }
     802             : 
     803             : /**
     804             :  * Copy a hx509 name object.
     805             :  *
     806             :  * @param context A hx509 cotext.
     807             :  * @param from the name to copy from
     808             :  * @param to the name to copy to
     809             :  *
     810             :  * @return An hx509 error code, see hx509_get_error_string().
     811             :  *
     812             :  * @ingroup hx509_name
     813             :  */
     814             : 
     815             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     816           0 : hx509_name_copy(hx509_context context, const hx509_name from, hx509_name *to)
     817             : {
     818           0 :     int ret;
     819             : 
     820           0 :     *to = calloc(1, sizeof(**to));
     821           0 :     if (*to == NULL)
     822           0 :         return ENOMEM;
     823           0 :     ret = copy_Name(&from->der_name, &(*to)->der_name);
     824           0 :     if (ret) {
     825           0 :         free(*to);
     826           0 :         *to = NULL;
     827           0 :         return ENOMEM;
     828             :     }
     829           0 :     return 0;
     830             : }
     831             : 
     832             : /**
     833             :  * Convert a hx509_name into a Name.
     834             :  *
     835             :  * @param from the name to copy from
     836             :  * @param to the name to copy to
     837             :  *
     838             :  * @return An hx509 error code, see hx509_get_error_string().
     839             :  *
     840             :  * @ingroup hx509_name
     841             :  */
     842             : 
     843             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     844         121 : hx509_name_to_Name(const hx509_name from, Name *to)
     845             : {
     846         121 :     return copy_Name(&from->der_name, to);
     847             : }
     848             : 
     849             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     850           0 : hx509_name_normalize(hx509_context context, hx509_name name)
     851             : {
     852           0 :     return 0;
     853             : }
     854             : 
     855             : /**
     856             :  * Expands variables in the name using env. Variables are on the form
     857             :  * ${name}. Useful when dealing with certificate templates.
     858             :  *
     859             :  * @param context A hx509 cotext.
     860             :  * @param name the name to expand.
     861             :  * @param env environment variable to expand.
     862             :  *
     863             :  * @return An hx509 error code, see hx509_get_error_string().
     864             :  *
     865             :  * @ingroup hx509_name
     866             :  */
     867             : 
     868             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     869           0 : hx509_name_expand(hx509_context context,
     870             :                   hx509_name name,
     871             :                   hx509_env env)
     872             : {
     873           0 :     Name *n = &name->der_name;
     874           0 :     size_t i, j;
     875           0 :     int bounds_check = 1;
     876             : 
     877           0 :     if (env == NULL)
     878           0 :         return 0;
     879             : 
     880           0 :     if (n->element != choice_Name_rdnSequence) {
     881           0 :         hx509_set_error_string(context, 0, EINVAL, "RDN not of supported type");
     882           0 :         return EINVAL;
     883             :     }
     884             : 
     885           0 :     for (i = 0 ; i < n->u.rdnSequence.len; i++) {
     886           0 :         for (j = 0; j < n->u.rdnSequence.val[i].len; j++) {
     887             :             /** Only UTF8String rdnSequence names are allowed */
     888             :             /*
     889             :               THIS SHOULD REALLY BE:
     890             :               COMP = n->u.rdnSequence.val[i].val[j];
     891             :               normalize COMP to utf8
     892             :               check if there are variables
     893             :                 expand variables
     894             :                 convert back to orignal format, store in COMP
     895             :               free normalized utf8 string
     896             :             */
     897           0 :             DirectoryString *ds = &n->u.rdnSequence.val[i].val[j].value;
     898           0 :             heim_oid *type = &n->u.rdnSequence.val[i].val[j].type;
     899           0 :             const char *sval = NULL;
     900           0 :             char *p, *p2;
     901           0 :             char *s = NULL;
     902           0 :             struct rk_strpool *strpool = NULL;
     903             : 
     904           0 :             switch (ds->element) {
     905           0 :             case choice_DirectoryString_utf8String:
     906           0 :                 sval = ds->u.utf8String;
     907           0 :                 break;
     908           0 :             case choice_DirectoryString_teletexString:
     909           0 :                 sval = ds->u.utf8String;
     910           0 :                 break;
     911           0 :             case choice_DirectoryString_ia5String:
     912           0 :                 s = strndup(ds->u.ia5String.data,
     913             :                             ds->u.ia5String.length);
     914           0 :                 break;
     915           0 :             case choice_DirectoryString_printableString:
     916           0 :                 s = strndup(ds->u.printableString.data,
     917             :                             ds->u.printableString.length);
     918           0 :                 break;
     919           0 :             case choice_DirectoryString_universalString:
     920           0 :                 hx509_set_error_string(context, 0, ENOTSUP, "UniversalString not supported");
     921           0 :                 return ENOTSUP;
     922           0 :             case choice_DirectoryString_bmpString:
     923           0 :                 hx509_set_error_string(context, 0, ENOTSUP, "BMPString not supported");
     924           0 :                 return ENOTSUP;
     925             :             }
     926           0 :             if (sval == NULL && s == NULL)
     927           0 :                 return hx509_enomem(context);
     928           0 :             if (s)
     929           0 :                 sval = s;
     930             : 
     931           0 :             p = strstr(sval, "${");
     932           0 :             if (p) {
     933           0 :                 strpool = rk_strpoolprintf(strpool, "%.*s", (int)(p - sval), sval);
     934           0 :                 if (strpool == NULL) {
     935           0 :                     hx509_set_error_string(context, 0, ENOMEM, "out of memory");
     936           0 :                     free(s);
     937           0 :                     return ENOMEM;
     938             :                 }
     939             :             }
     940             : 
     941           0 :             while (p != NULL) {
     942             :                 /* expand variables */
     943           0 :                 const char *value;
     944           0 :                 p2 = strchr(p, '}');
     945           0 :                 if (p2 == NULL) {
     946           0 :                     hx509_set_error_string(context, 0, EINVAL, "missing }");
     947           0 :                     rk_strpoolfree(strpool);
     948           0 :                     free(s);
     949           0 :                     return EINVAL;
     950             :                 }
     951           0 :                 p += 2;
     952           0 :                 value = hx509_env_lfind(context, env, p, p2 - p);
     953           0 :                 if (value == NULL) {
     954           0 :                     hx509_set_error_string(context, 0, EINVAL,
     955             :                                            "variable %.*s missing",
     956           0 :                                            (int)(p2 - p), p);
     957           0 :                     rk_strpoolfree(strpool);
     958           0 :                     free(s);
     959           0 :                     return EINVAL;
     960             :                 }
     961           0 :                 strpool = rk_strpoolprintf(strpool, "%s", value);
     962           0 :                 if (strpool == NULL) {
     963           0 :                     hx509_set_error_string(context, 0, ENOMEM, "out of memory");
     964           0 :                     free(s);
     965           0 :                     return ENOMEM;
     966             :                 }
     967           0 :                 p2++;
     968             : 
     969           0 :                 p = strstr(p2, "${");
     970           0 :                 if (p)
     971           0 :                     strpool = rk_strpoolprintf(strpool, "%.*s",
     972           0 :                                                (int)(p - p2), p2);
     973             :                 else
     974           0 :                     strpool = rk_strpoolprintf(strpool, "%s", p2);
     975           0 :                 if (strpool == NULL) {
     976           0 :                     hx509_set_error_string(context, 0, ENOMEM, "out of memory");
     977           0 :                     free(s);
     978           0 :                     return ENOMEM;
     979             :                 }
     980             :             }
     981             : 
     982           0 :             free(s);
     983           0 :             s = NULL;
     984             : 
     985           0 :             if (strpool) {
     986           0 :                 size_t max_bytes;
     987             : 
     988           0 :                 if ((s = rk_strpoolcollect(strpool)) == NULL) {
     989           0 :                     hx509_set_error_string(context, 0, ENOMEM, "out of memory");
     990           0 :                     return ENOMEM;
     991             :                 }
     992             : 
     993             :                 /* Check upper bounds! */
     994           0 :                 if ((max_bytes = oidtomaxlen(type)) && strlen(s) > max_bytes)
     995           0 :                     bounds_check = 0;
     996             : 
     997           0 :                 switch (ds->element) {
     998             :                 /* C strings: */
     999           0 :                 case choice_DirectoryString_utf8String:
    1000           0 :                     free(ds->u.utf8String);
    1001           0 :                     ds->u.utf8String = s;
    1002           0 :                     break;
    1003           0 :                 case choice_DirectoryString_teletexString:
    1004           0 :                     free(ds->u.teletexString);
    1005           0 :                     ds->u.teletexString = s;
    1006           0 :                     break;
    1007             : 
    1008             :                 /* Length and pointer */
    1009           0 :                 case choice_DirectoryString_ia5String:
    1010           0 :                     free(ds->u.ia5String.data);
    1011           0 :                     ds->u.ia5String.data = s;
    1012           0 :                     ds->u.ia5String.length = strlen(s);
    1013           0 :                     break;
    1014           0 :                 case choice_DirectoryString_printableString:
    1015           0 :                     free(ds->u.printableString.data);
    1016           0 :                     ds->u.printableString.data = s;
    1017           0 :                     ds->u.printableString.length = strlen(s);
    1018           0 :                     break;
    1019           0 :                 default:
    1020           0 :                     break; /* Handled above */
    1021             :                 }
    1022             :             }
    1023             :         }
    1024             :     }
    1025             : 
    1026           0 :     if (!bounds_check) {
    1027           0 :         hx509_set_error_string(context, 0, HX509_PARSING_NAME_FAILED,
    1028             :                                "some expanded RDNs are too long");
    1029           0 :         return HX509_PARSING_NAME_FAILED;
    1030             :     }
    1031           0 :     return 0;
    1032             : }
    1033             : 
    1034             : /**
    1035             :  * Free a hx509 name object, upond return *name will be NULL.
    1036             :  *
    1037             :  * @param name a hx509 name object to be freed.
    1038             :  *
    1039             :  * @ingroup hx509_name
    1040             :  */
    1041             : 
    1042             : HX509_LIB_FUNCTION void HX509_LIB_CALL
    1043         354 : hx509_name_free(hx509_name *name)
    1044             : {
    1045         354 :     free_Name(&(*name)->der_name);
    1046         354 :     memset(*name, 0, sizeof(**name));
    1047         354 :     free(*name);
    1048         354 :     *name = NULL;
    1049         354 : }
    1050             : 
    1051             : /**
    1052             :  * Convert a DER encoded name info a string.
    1053             :  *
    1054             :  * @param data data to a DER/BER encoded name
    1055             :  * @param length length of data
    1056             :  * @param str the resulting string, is NULL on failure.
    1057             :  *
    1058             :  * @return An hx509 error code, see hx509_get_error_string().
    1059             :  *
    1060             :  * @ingroup hx509_name
    1061             :  */
    1062             : 
    1063             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1064           0 : hx509_unparse_der_name(const void *data, size_t length, char **str)
    1065             : {
    1066           0 :     Name name;
    1067           0 :     int ret;
    1068             : 
    1069           0 :     *str = NULL;
    1070             : 
    1071           0 :     ret = decode_Name(data, length, &name, NULL);
    1072           0 :     if (ret)
    1073           0 :         return ret;
    1074           0 :     ret = _hx509_Name_to_string(&name, str);
    1075           0 :     free_Name(&name);
    1076           0 :     return ret;
    1077             : }
    1078             : 
    1079             : /**
    1080             :  * Convert a hx509_name object to DER encoded name.
    1081             :  *
    1082             :  * @param name name to concert
    1083             :  * @param os data to a DER encoded name, free the resulting octet
    1084             :  * string with hx509_xfree(os->data).
    1085             :  *
    1086             :  * @return An hx509 error code, see hx509_get_error_string().
    1087             :  *
    1088             :  * @ingroup hx509_name
    1089             :  */
    1090             : 
    1091             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1092           0 : hx509_name_binary(const hx509_name name, heim_octet_string *os)
    1093             : {
    1094           0 :     size_t size;
    1095           0 :     int ret;
    1096             : 
    1097           0 :     ASN1_MALLOC_ENCODE(Name, os->data, os->length, &name->der_name, &size, ret);
    1098           0 :     if (ret)
    1099           0 :         return ret;
    1100           0 :     if (os->length != size)
    1101           0 :         _hx509_abort("internal ASN.1 encoder error");
    1102             : 
    1103           0 :     return 0;
    1104             : }
    1105             : 
    1106             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1107           0 : _hx509_unparse_Name(const Name *aname, char **str)
    1108             : {
    1109           0 :     hx509_name name;
    1110           0 :     int ret;
    1111             : 
    1112           0 :     ret = _hx509_name_from_Name(aname, &name);
    1113           0 :     if (ret)
    1114           0 :         return ret;
    1115             : 
    1116           0 :     ret = hx509_name_to_string(name, str);
    1117           0 :     hx509_name_free(&name);
    1118           0 :     return ret;
    1119             : }
    1120             : 
    1121             : /**
    1122             :  * Check if a name is empty.
    1123             :  *
    1124             :  * @param name the name to check if its empty/null.
    1125             :  *
    1126             :  * @return non zero if the name is empty/null.
    1127             :  *
    1128             :  * @ingroup hx509_name
    1129             :  */
    1130             : 
    1131             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1132         121 : hx509_name_is_null_p(const hx509_name name)
    1133             : {
    1134         242 :     return name->der_name.element == choice_Name_rdnSequence &&
    1135         121 :         name->der_name.u.rdnSequence.len == 0;
    1136             : }
    1137             : 
    1138             : int
    1139           0 : _hx509_unparse_PermanentIdentifier(hx509_context context,
    1140             :                                    struct rk_strpool **strpool,
    1141             :                                    heim_any *value)
    1142             : {
    1143           0 :     PermanentIdentifier pi;
    1144           0 :     size_t len;
    1145           0 :     const char *pid = "";
    1146           0 :     char *s = NULL;
    1147           0 :     int ret;
    1148             : 
    1149           0 :     ret = decode_PermanentIdentifier(value->data, value->length, &pi, &len);
    1150           0 :     if (ret == 0 && pi.assigner &&
    1151           0 :         der_print_heim_oid(pi.assigner, '.', &s) != 0)
    1152           0 :         ret = hx509_enomem(context);
    1153           0 :     if (pi.identifierValue && *pi.identifierValue)
    1154           0 :         pid = *pi.identifierValue;
    1155           0 :     if (ret == 0 &&
    1156           0 :         (*strpool = rk_strpoolprintf(*strpool, "%s:%s", s ? s : "", pid)) == NULL)
    1157           0 :         ret = hx509_enomem(context);
    1158           0 :     free_PermanentIdentifier(&pi);
    1159           0 :     free(s);
    1160           0 :     if (ret) {
    1161           0 :         rk_strpoolfree(*strpool);
    1162           0 :         *strpool = rk_strpoolprintf(NULL,
    1163             :                                     "<error-decoding-PermanentIdentifier");
    1164           0 :         hx509_set_error_string(context, 0, ret,
    1165             :                                "Failed to decode PermanentIdentifier");
    1166             :     }
    1167           0 :     return ret;
    1168             : }
    1169             : 
    1170             : int
    1171           0 : _hx509_unparse_HardwareModuleName(hx509_context context,
    1172             :                                   struct rk_strpool **strpool,
    1173             :                                   heim_any *value)
    1174             : {
    1175           0 :     HardwareModuleName hm;
    1176           0 :     size_t len;
    1177           0 :     char *s = NULL;
    1178           0 :     int ret;
    1179             : 
    1180           0 :     ret = decode_HardwareModuleName(value->data, value->length, &hm, &len);
    1181           0 :     if (ret == 0 && hm.hwSerialNum.length > 256)
    1182           0 :         hm.hwSerialNum.length = 256;
    1183           0 :     if (ret == 0)
    1184           0 :         ret = der_print_heim_oid(&hm.hwType, '.', &s);
    1185           0 :     if (ret == 0) {
    1186           0 :         *strpool = rk_strpoolprintf(*strpool, "%s:%.*s%s", s,
    1187           0 :                                     (int)hm.hwSerialNum.length,
    1188           0 :                                     (char *)hm.hwSerialNum.data,
    1189           0 :                                     value->length == len ? "" : ", <garbage>");
    1190           0 :         if (*strpool == NULL)
    1191           0 :             ret = hx509_enomem(context);
    1192             :     }
    1193           0 :     free_HardwareModuleName(&hm);
    1194           0 :     free(s);
    1195           0 :     if (ret) {
    1196           0 :         rk_strpoolfree(*strpool);
    1197           0 :         *strpool = rk_strpoolprintf(NULL,
    1198             :                                     "<error-decoding-HardwareModuleName");
    1199           0 :         hx509_set_error_string(context, 0, ret,
    1200             :                                "Failed to decode HardwareModuleName");
    1201             :     }
    1202           0 :     return ret;
    1203             : }
    1204             : 
    1205             : /*
    1206             :  * This necessarily duplicates code from libkrb5, and has to unless we move
    1207             :  * common code here or to lib/roken for it.  We do have slightly different
    1208             :  * needs (e.g., we want space quoted, and we want to indicate whether we saw
    1209             :  * trailing garbage, we have no need for flags, no special realm treatment,
    1210             :  * etc) than the corresponding code in libkrb5, so for now we duplicate this
    1211             :  * code.
    1212             :  *
    1213             :  * The relevant RFCs here are RFC1964 for the string representation of Kerberos
    1214             :  * principal names, and RFC4556 for the KRB5PrincipalName ASN.1 type (Kerberos
    1215             :  * lacks such a type because on the wire the name and realm are sent
    1216             :  * separately as a form of cheap compression).
    1217             :  *
    1218             :  * Note that we cannot handle embedded NULs because of Heimdal's representation
    1219             :  * of ASN.1 strings as C strings.
    1220             :  */
    1221             : int
    1222           0 : _hx509_unparse_KRB5PrincipalName(hx509_context context,
    1223             :                                  struct rk_strpool **strpool,
    1224             :                                  heim_any *value)
    1225             : {
    1226           0 :     KRB5PrincipalName kn;
    1227           0 :     size_t len;
    1228           0 :     int ret;
    1229             : 
    1230           0 :     ret = decode_KRB5PrincipalName(value->data, value->length, &kn, &len);
    1231           0 :     if (ret == 0 &&
    1232           0 :         (*strpool = _hx509_unparse_kerberos_name(*strpool, &kn)) == NULL)
    1233           0 :         ret = hx509_enomem(context);
    1234           0 :     free_KRB5PrincipalName(&kn);
    1235           0 :     if (ret == 0 && (value->length != len) &&
    1236           0 :         (*strpool = rk_strpoolprintf(*strpool, " <garbage>")) == NULL)
    1237           0 :         ret = hx509_enomem(context);
    1238           0 :     if (ret) {
    1239           0 :         rk_strpoolfree(*strpool);
    1240           0 :         *strpool = rk_strpoolprintf(NULL,
    1241             :                                     "<error-decoding-PrincipalName");
    1242           0 :         hx509_set_error_string(context, 0, ret,
    1243             :                                "Failed to decode PermanentIdentifier");
    1244             :     }
    1245           0 :     return ret;
    1246             : }
    1247             : 
    1248             : struct rk_strpool *
    1249           0 : _hx509_unparse_kerberos_name(struct rk_strpool *strpool, KRB5PrincipalName *kn)
    1250             : {
    1251           0 :     static const char comp_quotable_chars[] = " \n\t\b\\/@";
    1252           0 :     static const char realm_quotable_chars[] = " \n\t\b\\@";
    1253           0 :     const char *s;
    1254           0 :     size_t i, k, len, plen;
    1255           0 :     int need_slash = 0;
    1256             : 
    1257           0 :     for (i = 0; i < kn->principalName.name_string.len; i++) {
    1258           0 :         s = kn->principalName.name_string.val[i];
    1259           0 :         len = strlen(s);
    1260             : 
    1261           0 :         if (need_slash)
    1262           0 :             strpool = rk_strpoolprintf(strpool, "/");
    1263           0 :         need_slash = 1;
    1264             : 
    1265           0 :         for (k = 0; k < len; s += plen, k += plen) {
    1266           0 :             char c;
    1267             : 
    1268           0 :             plen = strcspn(s, comp_quotable_chars);
    1269           0 :             if (plen)
    1270           0 :                 strpool = rk_strpoolprintf(strpool, "%.*s", (int)plen, s);
    1271           0 :             if (k + plen >= len)
    1272           0 :                 continue;
    1273           0 :             switch ((c = s[plen++])) {
    1274           0 :             case '\n':  strpool = rk_strpoolprintf(strpool, "\\n");     break;
    1275           0 :             case '\t':  strpool = rk_strpoolprintf(strpool, "\\t");     break;
    1276           0 :             case '\b':  strpool = rk_strpoolprintf(strpool, "\\b");     break;
    1277             :                         /* default -> '@', ' ', '\\', or '/' */
    1278           0 :             default:    strpool = rk_strpoolprintf(strpool, "\\%c", c); break;
    1279             :             }
    1280             :         }
    1281             :     }
    1282           0 :     if (!kn->realm)
    1283           0 :         return strpool;
    1284           0 :     strpool = rk_strpoolprintf(strpool, "@");
    1285             : 
    1286           0 :     s = kn->realm;
    1287           0 :     len = strlen(kn->realm);
    1288           0 :     for (k = 0; k < len; s += plen, k += plen) {
    1289           0 :         char c;
    1290             : 
    1291           0 :         plen = strcspn(s, realm_quotable_chars);
    1292           0 :         if (plen)
    1293           0 :             strpool = rk_strpoolprintf(strpool, "%.*s", (int)plen, s);
    1294           0 :         if (k + plen >= len)
    1295           0 :             continue;
    1296           0 :         switch ((c = s[plen++])) {
    1297           0 :         case '\n':  strpool = rk_strpoolprintf(strpool, "\\n");     break;
    1298           0 :         case '\t':  strpool = rk_strpoolprintf(strpool, "\\t");     break;
    1299           0 :         case '\b':  strpool = rk_strpoolprintf(strpool, "\\b");     break;
    1300             :                     /* default -> '@', ' ', or '\\' */
    1301           0 :         default:    strpool = rk_strpoolprintf(strpool, "\\%c", c); break;
    1302             :         }
    1303             :     }
    1304           0 :     return strpool;
    1305             : }
    1306             : 
    1307             : int
    1308           0 : _hx509_unparse_utf8_string_name(hx509_context context,
    1309             :                                 struct rk_strpool **strpool,
    1310             :                                 heim_any *value)
    1311             : {
    1312           0 :     PKIXXmppAddr us;
    1313           0 :     size_t size;
    1314           0 :     int ret;
    1315             : 
    1316           0 :     ret = decode_PKIXXmppAddr(value->data, value->length, &us, &size);
    1317           0 :     if (ret == 0 &&
    1318           0 :         (*strpool = rk_strpoolprintf(*strpool, "%s", us)) == NULL)
    1319           0 :         ret = hx509_enomem(context);
    1320           0 :     if (ret) {
    1321           0 :         rk_strpoolfree(*strpool);
    1322           0 :         *strpool = rk_strpoolprintf(NULL,
    1323             :                                     "<error-decoding-UTF8String-SAN>");
    1324           0 :         hx509_set_error_string(context, 0, ret,
    1325             :                                "Failed to decode UTF8String SAN");
    1326             :     }
    1327           0 :     free_PKIXXmppAddr(&us);
    1328           0 :     return ret;
    1329             : }
    1330             : 
    1331             : int
    1332           0 : _hx509_unparse_ia5_string_name(hx509_context context,
    1333             :                                struct rk_strpool **strpool,
    1334             :                                heim_any *value)
    1335             : {
    1336           0 :     SRVName us;
    1337           0 :     size_t size;
    1338           0 :     int ret;
    1339             : 
    1340           0 :     ret = decode_SRVName(value->data, value->length, &us, &size);
    1341           0 :     if (ret == 0) {
    1342           0 :         rk_strpoolfree(*strpool);
    1343           0 :         *strpool = rk_strpoolprintf(NULL,
    1344             :                                     "<error-decoding-IA5String-SAN>");
    1345           0 :         hx509_set_error_string(context, 0, ret,
    1346             :                                "Failed to decode UTF8String SAN");
    1347           0 :         return ret;
    1348             :     }
    1349           0 :     *strpool = rk_strpoolprintf(*strpool, "%.*s",
    1350           0 :                                 (int)us.length, (char *)us.data);
    1351           0 :     free_SRVName(&us);
    1352           0 :     return ret;
    1353             : }
    1354             : 
    1355             : typedef int (*other_unparser_f)(hx509_context,
    1356             :                                 struct rk_strpool **,
    1357             :                                 heim_any *);
    1358             : 
    1359             : struct {
    1360             :     const heim_oid *oid;
    1361             :     const char *friendly_name;
    1362             :     other_unparser_f f;
    1363             : } o_unparsers[] = {
    1364             :     { &asn1_oid_id_pkinit_san,
    1365             :         "KerberosPrincipalName",
    1366             :         _hx509_unparse_KRB5PrincipalName },
    1367             :     { &asn1_oid_id_pkix_on_permanentIdentifier,
    1368             :         "PermanentIdentifier",
    1369             :         _hx509_unparse_PermanentIdentifier },
    1370             :     { &asn1_oid_id_on_hardwareModuleName,
    1371             :         "HardwareModuleName",
    1372             :         _hx509_unparse_HardwareModuleName },
    1373             :     { &asn1_oid_id_pkix_on_xmppAddr,
    1374             :         "XMPPName",
    1375             :         _hx509_unparse_utf8_string_name },
    1376             :     { &asn1_oid_id_pkinit_ms_san,
    1377             :         "MSFTKerberosPrincipalName",
    1378             :         _hx509_unparse_utf8_string_name },
    1379             :     { &asn1_oid_id_pkix_on_dnsSRV,
    1380             :         "SRVName",
    1381             :         _hx509_unparse_ia5_string_name },
    1382             : };
    1383             : 
    1384             : /**
    1385             :  * Unparse the hx509 name in name into a string.
    1386             :  *
    1387             :  * @param name the name to print
    1388             :  * @param str an allocated string returns the name in string form
    1389             :  *
    1390             :  * @return An hx509 error code, see hx509_get_error_string().
    1391             :  *
    1392             :  * @ingroup hx509_name
    1393             :  */
    1394             : 
    1395             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1396           0 : hx509_general_name_unparse(GeneralName *name, char **str)
    1397             : {
    1398           0 :     hx509_context context;
    1399           0 :     int ret;
    1400             : 
    1401           0 :     if ((ret = hx509_context_init(&context)))
    1402           0 :         return ret;
    1403           0 :     ret = hx509_general_name_unparse2(context, name, str);
    1404           0 :     hx509_context_free(&context);
    1405           0 :     return ret;
    1406             : }
    1407             : 
    1408             : /**
    1409             :  * Unparse the hx509 name in name into a string.
    1410             :  *
    1411             :  * @param context hx509 library context
    1412             :  * @param name the name to print
    1413             :  * @param str an allocated string returns the name in string form
    1414             :  *
    1415             :  * @return An hx509 error code, see hx509_get_error_string().
    1416             :  *
    1417             :  * @ingroup hx509_name
    1418             :  */
    1419             : 
    1420             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1421           0 : hx509_general_name_unparse2(hx509_context context,
    1422             :                             GeneralName *name,
    1423             :                             char **str)
    1424             : {
    1425           0 :     struct rk_strpool *strpool = NULL;
    1426           0 :     int ret = 0;
    1427             : 
    1428           0 :     *str = NULL;
    1429             : 
    1430           0 :     switch (name->element) {
    1431           0 :     case choice_GeneralName_otherName: {
    1432           0 :         size_t i;
    1433           0 :         char *oid;
    1434             : 
    1435           0 :         ret = hx509_oid_sprint(&name->u.otherName.type_id, &oid);
    1436           0 :         if (ret == 0)
    1437           0 :             strpool = rk_strpoolprintf(strpool, "otherName: %s ", oid);
    1438           0 :         if (strpool == NULL)
    1439           0 :             ret = ENOMEM;
    1440             : 
    1441           0 :         for (i = 0; ret == 0 && i < sizeof(o_unparsers)/sizeof(o_unparsers[0]); i++) {
    1442           0 :             if (der_heim_oid_cmp(&name->u.otherName.type_id,
    1443             :                                  o_unparsers[i].oid))
    1444           0 :                 continue;
    1445           0 :             strpool = rk_strpoolprintf(strpool, "%s ",o_unparsers[i].friendly_name);
    1446           0 :             if (strpool == NULL)
    1447           0 :                 ret = ENOMEM;
    1448           0 :             if (ret == 0)
    1449           0 :                 ret = o_unparsers[i].f(context, &strpool, &name->u.otherName.value);
    1450           0 :             break;
    1451             :         }
    1452           0 :         if (ret == 0 && i == sizeof(o_unparsers)/sizeof(o_unparsers[0])) {
    1453           0 :             strpool = rk_strpoolprintf(strpool, "<unknown-other-name-type>");
    1454           0 :             ret = ENOTSUP;
    1455             :         }
    1456           0 :         free(oid);
    1457           0 :         break;
    1458             :     }
    1459           0 :     case choice_GeneralName_rfc822Name:
    1460           0 :         strpool = rk_strpoolprintf(strpool, "rfc822Name: %.*s",
    1461           0 :                                    (int)name->u.rfc822Name.length,
    1462           0 :                                    (char *)name->u.rfc822Name.data);
    1463           0 :         break;
    1464           0 :     case choice_GeneralName_dNSName:
    1465           0 :         strpool = rk_strpoolprintf(strpool, "dNSName: %.*s",
    1466           0 :                                    (int)name->u.dNSName.length,
    1467           0 :                                    (char *)name->u.dNSName.data);
    1468           0 :         break;
    1469           0 :     case choice_GeneralName_directoryName: {
    1470           0 :         Name dir;
    1471           0 :         char *s;
    1472           0 :         memset(&dir, 0, sizeof(dir));
    1473           0 :         dir.element = (enum Name_enum)name->u.directoryName.element;
    1474           0 :         dir.u.rdnSequence = name->u.directoryName.u.rdnSequence;
    1475           0 :         ret = _hx509_unparse_Name(&dir, &s);
    1476           0 :         if (ret)
    1477           0 :             return ret;
    1478           0 :         strpool = rk_strpoolprintf(strpool, "directoryName: %s", s);
    1479           0 :         free(s);
    1480           0 :         break;
    1481             :     }
    1482           0 :     case choice_GeneralName_uniformResourceIdentifier:
    1483           0 :         strpool = rk_strpoolprintf(strpool, "URI: %.*s",
    1484           0 :                                    (int)name->u.uniformResourceIdentifier.length,
    1485           0 :                                    (char *)name->u.uniformResourceIdentifier.data);
    1486           0 :         break;
    1487           0 :     case choice_GeneralName_iPAddress: {
    1488           0 :         unsigned char *a = name->u.iPAddress.data;
    1489             : 
    1490           0 :         strpool = rk_strpoolprintf(strpool, "IPAddress: ");
    1491           0 :         if (strpool == NULL)
    1492           0 :             break;
    1493           0 :         if (name->u.iPAddress.length == 4)
    1494           0 :             strpool = rk_strpoolprintf(strpool, "%d.%d.%d.%d",
    1495           0 :                                        a[0], a[1], a[2], a[3]);
    1496           0 :         else if (name->u.iPAddress.length == 16)
    1497           0 :             strpool = rk_strpoolprintf(strpool,
    1498             :                                        "%02X:%02X:%02X:%02X:"
    1499             :                                        "%02X:%02X:%02X:%02X:"
    1500             :                                        "%02X:%02X:%02X:%02X:"
    1501             :                                        "%02X:%02X:%02X:%02X",
    1502           0 :                                        a[0], a[1], a[2], a[3],
    1503           0 :                                        a[4], a[5], a[6], a[7],
    1504           0 :                                        a[8], a[9], a[10], a[11],
    1505           0 :                                        a[12], a[13], a[14], a[15]);
    1506             :         else
    1507           0 :             strpool = rk_strpoolprintf(strpool,
    1508             :                                        "unknown IP address of length %lu",
    1509           0 :                                        (unsigned long)name->u.iPAddress.length);
    1510           0 :         break;
    1511             :     }
    1512           0 :     case choice_GeneralName_registeredID: {
    1513           0 :         char *oid;
    1514           0 :         hx509_oid_sprint(&name->u.registeredID, &oid);
    1515           0 :         if (oid == NULL)
    1516           0 :             return ENOMEM;
    1517           0 :         strpool = rk_strpoolprintf(strpool, "registeredID: %s", oid);
    1518           0 :         free(oid);
    1519           0 :         break;
    1520             :     }
    1521           0 :     default:
    1522           0 :         return EINVAL;
    1523             :     }
    1524           0 :     if (ret)
    1525           0 :         rk_strpoolfree(strpool);
    1526           0 :     else if (strpool == NULL || (*str = rk_strpoolcollect(strpool)) == NULL)
    1527           0 :         return ENOMEM;
    1528           0 :     return ret;
    1529             : }

Generated by: LCOV version 1.14