~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/lib/hx509/name.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2004 - 2007 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
RCSID("$Id$");
 
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 serveral 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)(void);
 
67
    wind_profile_flags flags;
 
68
} no[] = {
 
69
    { "C", oid_id_at_countryName },
 
70
    { "CN", oid_id_at_commonName },
 
71
    { "DC", oid_id_domainComponent },
 
72
    { "L", oid_id_at_localityName },
 
73
    { "O", oid_id_at_organizationName },
 
74
    { "OU", oid_id_at_organizationalUnitName },
 
75
    { "S", oid_id_at_stateOrProvinceName },
 
76
    { "STREET", oid_id_at_streetAddress },
 
77
    { "UID", oid_id_Userid },
 
78
    { "emailAddress", oid_id_pkcs9_emailAddress },
 
79
    { "serialNumber", oid_id_at_serialNumber }
 
80
};
 
81
 
 
82
static char *
 
83
quote_string(const char *f, size_t len, size_t *rlen)
 
84
{
 
85
    size_t i, j, tolen;
 
86
    const char *from = f;
 
87
    char *to;
 
88
 
 
89
    tolen = len * 3 + 1;
 
90
    to = malloc(tolen);
 
91
    if (to == NULL)
 
92
        return NULL;
 
93
 
 
94
    for (i = 0, j = 0; i < len; i++) {
 
95
        if (from[i] == ' ' && i + 1 < len)
 
96
            to[j++] = from[i];
 
97
        else if (from[i] == ',' || from[i] == '=' || from[i] == '+' ||
 
98
                 from[i] == '<' || from[i] == '>' || from[i] == '#' ||
 
99
                 from[i] == ';' || from[i] == ' ')
 
100
        {
 
101
            to[j++] = '\\';
 
102
            to[j++] = from[i];
 
103
        } else if (((unsigned char)from[i]) >= 32 && ((unsigned char)from[i]) <= 127) {
 
104
            to[j++] = from[i];
 
105
        } else {
 
106
            int l = snprintf(&to[j], tolen - j - 1,
 
107
                             "#%02x", (unsigned char)from[i]);
 
108
            j += l;
 
109
        }
 
110
    }
 
111
    to[j] = '\0';
 
112
    assert(j < tolen);
 
113
    *rlen = j;
 
114
    return to;
 
115
}
 
116
 
 
117
 
 
118
static int
 
119
append_string(char **str, size_t *total_len, const char *ss,
 
120
              size_t len, int quote)
 
121
{
 
122
    char *s, *qs;
 
123
 
 
124
    if (quote)
 
125
        qs = quote_string(ss, len, &len);
 
126
    else
 
127
        qs = rk_UNCONST(ss);
 
128
 
 
129
    s = realloc(*str, len + *total_len + 1);
 
130
    if (s == NULL)
 
131
        _hx509_abort("allocation failure"); /* XXX */
 
132
    memcpy(s + *total_len, qs, len);
 
133
    if (qs != ss)
 
134
        free(qs);
 
135
    s[*total_len + len] = '\0';
 
136
    *str = s;
 
137
    *total_len += len;
 
138
    return 0;
 
139
}
 
140
 
 
141
static char *
 
142
oidtostring(const heim_oid *type)
 
143
{
 
144
    char *s;
 
145
    size_t i;
 
146
 
 
147
    for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) {
 
148
        if (der_heim_oid_cmp((*no[i].o)(), type) == 0)
 
149
            return strdup(no[i].n);
 
150
    }
 
151
    if (der_print_heim_oid(type, '.', &s) != 0)
 
152
        return NULL;
 
153
    return s;
 
154
}
 
155
 
 
156
static int
 
157
stringtooid(const char *name, size_t len, heim_oid *oid)
 
158
{
 
159
    int i, ret;
 
160
    char *s;
 
161
 
 
162
    memset(oid, 0, sizeof(*oid));
 
163
 
 
164
    for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) {
 
165
        if (strncasecmp(no[i].n, name, len) == 0)
 
166
            return der_copy_oid((*no[i].o)(), oid);
 
167
    }
 
168
    s = malloc(len + 1);
 
169
    if (s == NULL)
 
170
        return ENOMEM;
 
171
    memcpy(s, name, len);
 
172
    s[len] = '\0';
 
173
    ret = der_parse_heim_oid(s, ".", oid);
 
174
    free(s);
 
175
    return ret;
 
176
}
 
177
 
 
178
/**
 
179
 * Convert the hx509 name object into a printable string.
 
180
 * The resulting string should be freed with free().
 
181
 *
 
182
 * @param name name to print
 
183
 * @param str the string to return
 
184
 *
 
185
 * @return An hx509 error code, see hx509_get_error_string().
 
186
 *
 
187
 * @ingroup hx509_name
 
188
 */
 
189
 
 
190
int
 
191
hx509_name_to_string(const hx509_name name, char **str)
 
192
{
 
193
    return _hx509_Name_to_string(&name->der_name, str);
 
194
}
 
195
 
 
196
int
 
197
_hx509_Name_to_string(const Name *n, char **str)
 
198
{
 
199
    size_t total_len = 0;
 
200
    int i, j;
 
201
 
 
202
    *str = strdup("");
 
203
    if (*str == NULL)
 
204
        return ENOMEM;
 
205
 
 
206
    for (i = n->u.rdnSequence.len - 1 ; i >= 0 ; i--) {
 
207
        int len;
 
208
 
 
209
        for (j = 0; j < n->u.rdnSequence.val[i].len; j++) {
 
210
            DirectoryString *ds = &n->u.rdnSequence.val[i].val[j].value;
 
211
            char *oidname;
 
212
            char *ss;
 
213
        
 
214
            oidname = oidtostring(&n->u.rdnSequence.val[i].val[j].type);
 
215
 
 
216
            switch(ds->element) {
 
217
            case choice_DirectoryString_ia5String:
 
218
                ss = ds->u.ia5String;
 
219
                break;
 
220
            case choice_DirectoryString_printableString:
 
221
                ss = ds->u.printableString;
 
222
                break;
 
223
            case choice_DirectoryString_utf8String:
 
224
                ss = ds->u.utf8String;
 
225
                break;
 
226
            case choice_DirectoryString_bmpString: {
 
227
                uint16_t *bmp = ds->u.bmpString.data;
 
228
                size_t bmplen = ds->u.bmpString.length;
 
229
                size_t k;
 
230
 
 
231
                ss = malloc(bmplen + 1);
 
232
                if (ss == NULL)
 
233
                    _hx509_abort("allocation failure"); /* XXX */
 
234
                for (k = 0; k < bmplen; k++)
 
235
                    ss[k] = bmp[k] & 0xff; /* XXX */
 
236
                ss[k] = '\0';
 
237
                break;
 
238
            }
 
239
            case choice_DirectoryString_teletexString:
 
240
                ss = malloc(ds->u.teletexString.length + 1);
 
241
                if (ss == NULL)
 
242
                    _hx509_abort("allocation failure"); /* XXX */
 
243
                memcpy(ss, ds->u.teletexString.data, ds->u.teletexString.length);
 
244
                ss[ds->u.teletexString.length] = '\0';
 
245
                break;
 
246
            case choice_DirectoryString_universalString: {
 
247
                uint32_t *uni = ds->u.universalString.data;
 
248
                size_t unilen = ds->u.universalString.length;
 
249
                size_t k;
 
250
 
 
251
                ss = malloc(unilen + 1);
 
252
                if (ss == NULL)
 
253
                    _hx509_abort("allocation failure"); /* XXX */
 
254
                for (k = 0; k < unilen; k++)
 
255
                    ss[k] = uni[k] & 0xff; /* XXX */
 
256
                ss[k] = '\0';
 
257
                break;
 
258
            }
 
259
            default:
 
260
                _hx509_abort("unknown directory type: %d", ds->element);
 
261
                exit(1);
 
262
            }
 
263
            append_string(str, &total_len, oidname, strlen(oidname), 0);
 
264
            free(oidname);
 
265
            append_string(str, &total_len, "=", 1, 0);
 
266
            len = strlen(ss);
 
267
            append_string(str, &total_len, ss, len, 1);
 
268
            if (ds->element == choice_DirectoryString_universalString ||
 
269
                ds->element == choice_DirectoryString_bmpString ||
 
270
                ds->element == choice_DirectoryString_teletexString)
 
271
            {
 
272
                free(ss);
 
273
            }
 
274
            if (j + 1 < n->u.rdnSequence.val[i].len)
 
275
                append_string(str, &total_len, "+", 1, 0);
 
276
        }
 
277
 
 
278
        if (i > 0)
 
279
            append_string(str, &total_len, ",", 1, 0);
 
280
    }
 
281
    return 0;
 
282
}
 
283
 
 
284
#define COPYCHARARRAY(_ds,_el,_l,_n)            \
 
285
        (_l) = strlen(_ds->u._el);              \
 
286
        (_n) = malloc((_l) * sizeof((_n)[0]));  \
 
287
        if ((_n) == NULL)                       \
 
288
            return ENOMEM;                      \
 
289
        for (i = 0; i < (_l); i++)              \
 
290
            (_n)[i] = _ds->u._el[i]
 
291
 
 
292
 
 
293
#define COPYVALARRAY(_ds,_el,_l,_n)             \
 
294
        (_l) = _ds->u._el.length;               \
 
295
        (_n) = malloc((_l) * sizeof((_n)[0]));  \
 
296
        if ((_n) == NULL)                       \
 
297
            return ENOMEM;                      \
 
298
        for (i = 0; i < (_l); i++)              \
 
299
            (_n)[i] = _ds->u._el.data[i]
 
300
 
 
301
#define COPYVOIDARRAY(_ds,_el,_l,_n)            \
 
302
        (_l) = _ds->u._el.length;               \
 
303
        (_n) = malloc((_l) * sizeof((_n)[0]));  \
 
304
        if ((_n) == NULL)                       \
 
305
            return ENOMEM;                      \
 
306
        for (i = 0; i < (_l); i++)              \
 
307
            (_n)[i] = ((unsigned char *)_ds->u._el.data)[i]
 
308
 
 
309
 
 
310
 
 
311
static int
 
312
dsstringprep(const DirectoryString *ds, uint32_t **rname, size_t *rlen)
 
313
{
 
314
    wind_profile_flags flags = 0;
 
315
    size_t i, len;
 
316
    int ret;
 
317
    uint32_t *name;
 
318
 
 
319
    *rname = NULL;
 
320
    *rlen = 0;
 
321
 
 
322
    switch(ds->element) {
 
323
    case choice_DirectoryString_ia5String:
 
324
        COPYCHARARRAY(ds, ia5String, len, name);
 
325
        break;
 
326
    case choice_DirectoryString_printableString:
 
327
        flags = WIND_PROFILE_LDAP_CASE_EXACT_ATTRIBUTE;
 
328
        COPYCHARARRAY(ds, printableString, len, name);
 
329
        break;
 
330
    case choice_DirectoryString_teletexString:
 
331
        COPYVOIDARRAY(ds, teletexString, len, name);
 
332
        break;
 
333
    case choice_DirectoryString_bmpString:
 
334
        COPYVALARRAY(ds, bmpString, len, name);
 
335
        break;
 
336
    case choice_DirectoryString_universalString:
 
337
        COPYVALARRAY(ds, universalString, len, name);
 
338
        break;
 
339
    case choice_DirectoryString_utf8String:
 
340
        ret = wind_utf8ucs4_length(ds->u.utf8String, &len);
 
341
        if (ret)
 
342
            return ret;
 
343
        name = malloc(len * sizeof(name[0]));
 
344
        if (name == NULL)
 
345
            return ENOMEM;
 
346
        ret = wind_utf8ucs4(ds->u.utf8String, name, &len);
 
347
        if (ret)
 
348
            return ret;
 
349
        break;
 
350
    default:
 
351
        _hx509_abort("unknown directory type: %d", ds->element);
 
352
    }
 
353
 
 
354
    *rlen = len;
 
355
    /* try a couple of times to get the length right, XXX gross */
 
356
    for (i = 0; i < 4; i++) {
 
357
        *rlen = *rlen * 2;
 
358
        *rname = malloc(*rlen * sizeof((*rname)[0]));
 
359
 
 
360
        ret = wind_stringprep(name, len, *rname, rlen,
 
361
                              WIND_PROFILE_LDAP|flags);
 
362
        if (ret == WIND_ERR_OVERRUN) {
 
363
            free(*rname);
 
364
            *rname = NULL;
 
365
            continue;
 
366
        } else
 
367
            break;
 
368
    }
 
369
    free(name);
 
370
    if (ret) {
 
371
        if (*rname)
 
372
            free(*rname);
 
373
        *rname = NULL;
 
374
        *rlen = 0;
 
375
        return ret;
 
376
    }
 
377
 
 
378
    return 0;
 
379
}
 
380
 
 
381
int
 
382
_hx509_name_ds_cmp(const DirectoryString *ds1,
 
383
                   const DirectoryString *ds2,
 
384
                   int *diff)
 
385
{
 
386
    uint32_t *ds1lp, *ds2lp;
 
387
    size_t ds1len, ds2len;
 
388
    int ret;
 
389
 
 
390
    ret = dsstringprep(ds1, &ds1lp, &ds1len);
 
391
    if (ret)
 
392
        return ret;
 
393
    ret = dsstringprep(ds2, &ds2lp, &ds2len);
 
394
    if (ret) {
 
395
        free(ds1lp);
 
396
        return ret;
 
397
    }
 
398
 
 
399
    if (ds1len != ds2len)
 
400
        *diff = ds1len - ds2len;
 
401
    else
 
402
        *diff = memcmp(ds1lp, ds2lp, ds1len * sizeof(ds1lp[0]));
 
403
 
 
404
    free(ds1lp);
 
405
    free(ds2lp);
 
406
 
 
407
    return 0;
 
408
}
 
409
 
 
410
int
 
411
_hx509_name_cmp(const Name *n1, const Name *n2, int *c)
 
412
{
 
413
    int ret, i, j;
 
414
 
 
415
    *c = n1->u.rdnSequence.len - n2->u.rdnSequence.len;
 
416
    if (*c)
 
417
        return 0;
 
418
 
 
419
    for (i = 0 ; i < n1->u.rdnSequence.len; i++) {
 
420
        *c = n1->u.rdnSequence.val[i].len - n2->u.rdnSequence.val[i].len;
 
421
        if (*c)
 
422
            return 0;
 
423
 
 
424
        for (j = 0; j < n1->u.rdnSequence.val[i].len; j++) {
 
425
            *c = der_heim_oid_cmp(&n1->u.rdnSequence.val[i].val[j].type,
 
426
                                  &n1->u.rdnSequence.val[i].val[j].type);
 
427
            if (*c)
 
428
                return 0;
 
429
                        
 
430
            ret = _hx509_name_ds_cmp(&n1->u.rdnSequence.val[i].val[j].value,
 
431
                                     &n2->u.rdnSequence.val[i].val[j].value,
 
432
                                     c);
 
433
            if (ret)
 
434
                return ret;
 
435
            if (*c)
 
436
                return 0;
 
437
        }
 
438
    }
 
439
    *c = 0;
 
440
    return 0;
 
441
}
 
442
 
 
443
/**
 
444
 * Compare to hx509 name object, useful for sorting.
 
445
 *
 
446
 * @param n1 a hx509 name object.
 
447
 * @param n2 a hx509 name object.
 
448
 *
 
449
 * @return 0 the objects are the same, returns > 0 is n2 is "larger"
 
450
 * then n2, < 0 if n1 is "smaller" then n2.
 
451
 *
 
452
 * @ingroup hx509_name
 
453
 */
 
454
 
 
455
int
 
456
hx509_name_cmp(hx509_name n1, hx509_name n2)
 
457
{
 
458
    int ret, diff;
 
459
    ret = _hx509_name_cmp(&n1->der_name, &n2->der_name, &diff);
 
460
    if (ret)
 
461
        return ret;
 
462
    return diff;
 
463
}
 
464
 
 
465
 
 
466
int
 
467
_hx509_name_from_Name(const Name *n, hx509_name *name)
 
468
{
 
469
    int ret;
 
470
    *name = calloc(1, sizeof(**name));
 
471
    if (*name == NULL)
 
472
        return ENOMEM;
 
473
    ret = copy_Name(n, &(*name)->der_name);
 
474
    if (ret) {
 
475
        free(*name);
 
476
        *name = NULL;
 
477
    }
 
478
    return ret;
 
479
}
 
480
 
 
481
int
 
482
_hx509_name_modify(hx509_context context,
 
483
                   Name *name,
 
484
                   int append,
 
485
                   const heim_oid *oid,
 
486
                   const char *str)
 
487
{
 
488
    RelativeDistinguishedName *rdn;
 
489
    int ret;
 
490
    void *ptr;
 
491
 
 
492
    ptr = realloc(name->u.rdnSequence.val,
 
493
                  sizeof(name->u.rdnSequence.val[0]) *
 
494
                  (name->u.rdnSequence.len + 1));
 
495
    if (ptr == NULL) {
 
496
        hx509_set_error_string(context, 0, ENOMEM, "Out of memory");
 
497
        return ENOMEM;
 
498
    }
 
499
    name->u.rdnSequence.val = ptr;
 
500
 
 
501
    if (append) {
 
502
        rdn = &name->u.rdnSequence.val[name->u.rdnSequence.len];
 
503
    } else {
 
504
        memmove(&name->u.rdnSequence.val[1],
 
505
                &name->u.rdnSequence.val[0],
 
506
                name->u.rdnSequence.len *
 
507
                sizeof(name->u.rdnSequence.val[0]));
 
508
        
 
509
        rdn = &name->u.rdnSequence.val[0];
 
510
    }
 
511
    rdn->val = malloc(sizeof(rdn->val[0]));
 
512
    if (rdn->val == NULL)
 
513
        return ENOMEM;
 
514
    rdn->len = 1;
 
515
    ret = der_copy_oid(oid, &rdn->val[0].type);
 
516
    if (ret)
 
517
        return ret;
 
518
    rdn->val[0].value.element = choice_DirectoryString_utf8String;
 
519
    rdn->val[0].value.u.utf8String = strdup(str);
 
520
    if (rdn->val[0].value.u.utf8String == NULL)
 
521
        return ENOMEM;
 
522
    name->u.rdnSequence.len += 1;
 
523
 
 
524
    return 0;
 
525
}
 
526
 
 
527
/**
 
528
 * Parse a string into a hx509 name object.
 
529
 *
 
530
 * @param context A hx509 context.
 
531
 * @param str a string to parse.
 
532
 * @param name the resulting object, NULL in case of error.
 
533
 *
 
534
 * @return An hx509 error code, see hx509_get_error_string().
 
535
 *
 
536
 * @ingroup hx509_name
 
537
 */
 
538
 
 
539
int
 
540
hx509_parse_name(hx509_context context, const char *str, hx509_name *name)
 
541
{
 
542
    const char *p, *q;
 
543
    size_t len;
 
544
    hx509_name n;
 
545
    int ret;
 
546
 
 
547
    *name = NULL;
 
548
 
 
549
    n = calloc(1, sizeof(*n));
 
550
    if (n == NULL) {
 
551
        hx509_set_error_string(context, 0, ENOMEM, "out of memory");
 
552
        return ENOMEM;
 
553
    }
 
554
 
 
555
    n->der_name.element = choice_Name_rdnSequence;
 
556
 
 
557
    p = str;
 
558
 
 
559
    while (p != NULL && *p != '\0') {
 
560
        heim_oid oid;
 
561
        int last;
 
562
 
 
563
        q = strchr(p, ',');
 
564
        if (q) {
 
565
            len = (q - p);
 
566
            last = 1;
 
567
        } else {
 
568
            len = strlen(p);
 
569
            last = 0;
 
570
        }
 
571
 
 
572
        q = strchr(p, '=');
 
573
        if (q == NULL) {
 
574
            ret = HX509_PARSING_NAME_FAILED;
 
575
            hx509_set_error_string(context, 0, ret, "missing = in %s", p);
 
576
            goto out;
 
577
        }
 
578
        if (q == p) {
 
579
            ret = HX509_PARSING_NAME_FAILED;
 
580
            hx509_set_error_string(context, 0, ret,
 
581
                                   "missing name before = in %s", p);
 
582
            goto out;
 
583
        }
 
584
        
 
585
        if ((q - p) > len) {
 
586
            ret = HX509_PARSING_NAME_FAILED;
 
587
            hx509_set_error_string(context, 0, ret, " = after , in %s", p);
 
588
            goto out;
 
589
        }
 
590
 
 
591
        ret = stringtooid(p, q - p, &oid);
 
592
        if (ret) {
 
593
            ret = HX509_PARSING_NAME_FAILED;
 
594
            hx509_set_error_string(context, 0, ret,
 
595
                                   "unknown type: %.*s", (int)(q - p), p);
 
596
            goto out;
 
597
        }
 
598
        
 
599
        {
 
600
            size_t pstr_len = len - (q - p) - 1;
 
601
            const char *pstr = p + (q - p) + 1;
 
602
            char *r;
 
603
        
 
604
            r = malloc(pstr_len + 1);
 
605
            if (r == NULL) {
 
606
                der_free_oid(&oid);
 
607
                ret = ENOMEM;
 
608
                hx509_set_error_string(context, 0, ret, "out of memory");
 
609
                goto out;
 
610
            }
 
611
            memcpy(r, pstr, pstr_len);
 
612
            r[pstr_len] = '\0';
 
613
 
 
614
            ret = _hx509_name_modify(context, &n->der_name, 0, &oid, r);
 
615
            free(r);
 
616
            der_free_oid(&oid);
 
617
            if(ret)
 
618
                goto out;
 
619
        }
 
620
        p += len + last;
 
621
    }
 
622
 
 
623
    *name = n;
 
624
 
 
625
    return 0;
 
626
out:
 
627
    hx509_name_free(&n);
 
628
    return HX509_NAME_MALFORMED;
 
629
}
 
630
 
 
631
/**
 
632
 * Copy a hx509 name object.
 
633
 *
 
634
 * @param context A hx509 cotext.
 
635
 * @param from the name to copy from
 
636
 * @param to the name to copy to
 
637
 *
 
638
 * @return An hx509 error code, see hx509_get_error_string().
 
639
 *
 
640
 * @ingroup hx509_name
 
641
 */
 
642
 
 
643
int
 
644
hx509_name_copy(hx509_context context, const hx509_name from, hx509_name *to)
 
645
{
 
646
    int ret;
 
647
 
 
648
    *to = calloc(1, sizeof(**to));
 
649
    if (*to == NULL)
 
650
        return ENOMEM;
 
651
    ret = copy_Name(&from->der_name, &(*to)->der_name);
 
652
    if (ret) {
 
653
        free(*to);
 
654
        *to = NULL;
 
655
        return ENOMEM;
 
656
    }
 
657
    return 0;
 
658
}
 
659
 
 
660
/**
 
661
 * Convert a hx509_name into a Name.
 
662
 *
 
663
 * @param from the name to copy from
 
664
 * @param to the name to copy to
 
665
 *
 
666
 * @return An hx509 error code, see hx509_get_error_string().
 
667
 *
 
668
 * @ingroup hx509_name
 
669
 */
 
670
 
 
671
int
 
672
hx509_name_to_Name(const hx509_name from, Name *to)
 
673
{
 
674
    return copy_Name(&from->der_name, to);
 
675
}
 
676
 
 
677
int
 
678
hx509_name_normalize(hx509_context context, hx509_name name)
 
679
{
 
680
    return 0;
 
681
}
 
682
 
 
683
/**
 
684
 * Expands variables in the name using env. Variables are on the form
 
685
 * ${name}. Useful when dealing with certificate templates.
 
686
 *
 
687
 * @param context A hx509 cotext.
 
688
 * @param name the name to expand.
 
689
 * @param env environment variable to expand.
 
690
 *
 
691
 * @return An hx509 error code, see hx509_get_error_string().
 
692
 *
 
693
 * @ingroup hx509_name
 
694
 */
 
695
 
 
696
int
 
697
hx509_name_expand(hx509_context context,
 
698
                  hx509_name name,
 
699
                  hx509_env env)
 
700
{
 
701
    Name *n = &name->der_name;
 
702
    int i, j;
 
703
 
 
704
    if (env == NULL)
 
705
        return 0;
 
706
 
 
707
    if (n->element != choice_Name_rdnSequence) {
 
708
        hx509_set_error_string(context, 0, EINVAL, "RDN not of supported type");
 
709
        return EINVAL;
 
710
    }
 
711
 
 
712
    for (i = 0 ; i < n->u.rdnSequence.len; i++) {
 
713
        for (j = 0; j < n->u.rdnSequence.val[i].len; j++) {
 
714
            /** Only UTF8String rdnSequence names are allowed */
 
715
            /*
 
716
              THIS SHOULD REALLY BE:
 
717
              COMP = n->u.rdnSequence.val[i].val[j];
 
718
              normalize COMP to utf8
 
719
              check if there are variables
 
720
                expand variables
 
721
                convert back to orignal format, store in COMP
 
722
              free normalized utf8 string
 
723
            */
 
724
            DirectoryString *ds = &n->u.rdnSequence.val[i].val[j].value;
 
725
            char *p, *p2;
 
726
            struct rk_strpool *strpool = NULL;
 
727
 
 
728
            if (ds->element != choice_DirectoryString_utf8String) {
 
729
                hx509_set_error_string(context, 0, EINVAL, "unsupported type");
 
730
                return EINVAL;
 
731
            }
 
732
            p = strstr(ds->u.utf8String, "${");
 
733
            if (p) {
 
734
                strpool = rk_strpoolprintf(strpool, "%.*s",
 
735
                                           (int)(p - ds->u.utf8String),
 
736
                                           ds->u.utf8String);
 
737
                if (strpool == NULL) {
 
738
                    hx509_set_error_string(context, 0, ENOMEM, "out of memory");
 
739
                    return ENOMEM;
 
740
                }
 
741
            }
 
742
            while (p != NULL) {
 
743
                /* expand variables */
 
744
                const char *value;
 
745
                p2 = strchr(p, '}');
 
746
                if (p2 == NULL) {
 
747
                    hx509_set_error_string(context, 0, EINVAL, "missing }");
 
748
                    rk_strpoolfree(strpool);
 
749
                    return EINVAL;
 
750
                }
 
751
                p += 2;
 
752
                value = hx509_env_lfind(context, env, p, p2 - p);
 
753
                if (value == NULL) {
 
754
                    hx509_set_error_string(context, 0, EINVAL,
 
755
                                           "variable %.*s missing",
 
756
                                           (int)(p2 - p), p);
 
757
                    rk_strpoolfree(strpool);
 
758
                    return EINVAL;
 
759
                }
 
760
                strpool = rk_strpoolprintf(strpool, "%s", value);
 
761
                if (strpool == NULL) {
 
762
                    hx509_set_error_string(context, 0, ENOMEM, "out of memory");
 
763
                    return ENOMEM;
 
764
                }
 
765
                p2++;
 
766
 
 
767
                p = strstr(p2, "${");
 
768
                if (p)
 
769
                    strpool = rk_strpoolprintf(strpool, "%.*s",
 
770
                                               (int)(p - p2), p2);
 
771
                else
 
772
                    strpool = rk_strpoolprintf(strpool, "%s", p2);
 
773
                if (strpool == NULL) {
 
774
                    hx509_set_error_string(context, 0, ENOMEM, "out of memory");
 
775
                    return ENOMEM;
 
776
                }
 
777
            }
 
778
            if (strpool) {
 
779
                free(ds->u.utf8String);
 
780
                ds->u.utf8String = rk_strpoolcollect(strpool);
 
781
                if (ds->u.utf8String == NULL) {
 
782
                    hx509_set_error_string(context, 0, ENOMEM, "out of memory");
 
783
                    return ENOMEM;
 
784
                }
 
785
            }
 
786
        }
 
787
    }
 
788
    return 0;
 
789
}
 
790
 
 
791
/**
 
792
 * Free a hx509 name object, upond return *name will be NULL.
 
793
 *
 
794
 * @param name a hx509 name object to be freed.
 
795
 *
 
796
 * @ingroup hx509_name
 
797
 */
 
798
 
 
799
void
 
800
hx509_name_free(hx509_name *name)
 
801
{
 
802
    free_Name(&(*name)->der_name);
 
803
    memset(*name, 0, sizeof(**name));
 
804
    free(*name);
 
805
    *name = NULL;
 
806
}
 
807
 
 
808
/**
 
809
 * Convert a DER encoded name info a string.
 
810
 *
 
811
 * @param data data to a DER/BER encoded name
 
812
 * @param length length of data
 
813
 * @param str the resulting string, is NULL on failure.
 
814
 *
 
815
 * @return An hx509 error code, see hx509_get_error_string().
 
816
 *
 
817
 * @ingroup hx509_name
 
818
 */
 
819
 
 
820
int
 
821
hx509_unparse_der_name(const void *data, size_t length, char **str)
 
822
{
 
823
    Name name;
 
824
    int ret;
 
825
 
 
826
    *str = NULL;
 
827
 
 
828
    ret = decode_Name(data, length, &name, NULL);
 
829
    if (ret)
 
830
        return ret;
 
831
    ret = _hx509_Name_to_string(&name, str);
 
832
    free_Name(&name);
 
833
    return ret;
 
834
}
 
835
 
 
836
/**
 
837
 * Convert a hx509_name object to DER encoded name.
 
838
 *
 
839
 * @param name name to concert
 
840
 * @param os data to a DER encoded name, free the resulting octet
 
841
 * string with hx509_xfree(os->data).
 
842
 *
 
843
 * @return An hx509 error code, see hx509_get_error_string().
 
844
 *
 
845
 * @ingroup hx509_name
 
846
 */
 
847
 
 
848
int
 
849
hx509_name_binary(const hx509_name name, heim_octet_string *os)
 
850
{
 
851
    size_t size;
 
852
    int ret;
 
853
 
 
854
    ASN1_MALLOC_ENCODE(Name, os->data, os->length, &name->der_name, &size, ret);
 
855
    if (ret)
 
856
        return ret;
 
857
    if (os->length != size)
 
858
        _hx509_abort("internal ASN.1 encoder error");
 
859
 
 
860
    return 0;
 
861
}
 
862
 
 
863
int
 
864
_hx509_unparse_Name(const Name *aname, char **str)
 
865
{
 
866
    hx509_name name;
 
867
    int ret;
 
868
 
 
869
    ret = _hx509_name_from_Name(aname, &name);
 
870
    if (ret)
 
871
        return ret;
 
872
 
 
873
    ret = hx509_name_to_string(name, str);
 
874
    hx509_name_free(&name);
 
875
    return ret;
 
876
}
 
877
 
 
878
/**
 
879
 * Unparse the hx509 name in name into a string.
 
880
 *
 
881
 * @param name the name to check if its empty/null.
 
882
 *
 
883
 * @return non zero if the name is empty/null.
 
884
 *
 
885
 * @ingroup hx509_name
 
886
 */
 
887
 
 
888
int
 
889
hx509_name_is_null_p(const hx509_name name)
 
890
{
 
891
    return name->der_name.u.rdnSequence.len == 0;
 
892
}
 
893
 
 
894
/**
 
895
 * Unparse the hx509 name in name into a string.
 
896
 *
 
897
 * @param name the name to print
 
898
 * @param str an allocated string returns the name in string form
 
899
 *
 
900
 * @return An hx509 error code, see hx509_get_error_string().
 
901
 *
 
902
 * @ingroup hx509_name
 
903
 */
 
904
 
 
905
int
 
906
hx509_general_name_unparse(GeneralName *name, char **str)
 
907
{
 
908
    struct rk_strpool *strpool = NULL;
 
909
 
 
910
    *str = NULL;
 
911
 
 
912
    switch (name->element) {
 
913
    case choice_GeneralName_otherName: {
 
914
        char *str;
 
915
        hx509_oid_sprint(&name->u.otherName.type_id, &str);
 
916
        if (str == NULL)
 
917
            return ENOMEM;
 
918
        strpool = rk_strpoolprintf(strpool, "otherName: %s", str);
 
919
        free(str);
 
920
        break;
 
921
    }
 
922
    case choice_GeneralName_rfc822Name:
 
923
        strpool = rk_strpoolprintf(strpool, "rfc822Name: %s\n",
 
924
                                   name->u.rfc822Name);
 
925
        break;
 
926
    case choice_GeneralName_dNSName:
 
927
        strpool = rk_strpoolprintf(strpool, "dNSName: %s\n",
 
928
                                   name->u.dNSName);
 
929
        break;
 
930
    case choice_GeneralName_directoryName: {
 
931
        Name dir;
 
932
        char *s;
 
933
        int ret;
 
934
        memset(&dir, 0, sizeof(dir));
 
935
        dir.element = name->u.directoryName.element;
 
936
        dir.u.rdnSequence = name->u.directoryName.u.rdnSequence;
 
937
        ret = _hx509_unparse_Name(&dir, &s);
 
938
        if (ret)
 
939
            return ret;
 
940
        strpool = rk_strpoolprintf(strpool, "directoryName: %s", s);
 
941
        free(s);
 
942
        break;
 
943
    }
 
944
    case choice_GeneralName_uniformResourceIdentifier:
 
945
        strpool = rk_strpoolprintf(strpool, "URI: %s",
 
946
                                   name->u.uniformResourceIdentifier);
 
947
        break;
 
948
    case choice_GeneralName_iPAddress: {
 
949
        unsigned char *a = name->u.iPAddress.data;
 
950
 
 
951
        strpool = rk_strpoolprintf(strpool, "IPAddress: ");
 
952
        if (strpool == NULL)
 
953
            break;
 
954
        if (name->u.iPAddress.length == 4)
 
955
            strpool = rk_strpoolprintf(strpool, "%d.%d.%d.%d",
 
956
                                       a[0], a[1], a[2], a[3]);
 
957
        else if (name->u.iPAddress.length == 16)
 
958
            strpool = rk_strpoolprintf(strpool,
 
959
                                       "%02X:%02X:%02X:%02X:"
 
960
                                       "%02X:%02X:%02X:%02X:"
 
961
                                       "%02X:%02X:%02X:%02X:"
 
962
                                       "%02X:%02X:%02X:%02X",
 
963
                                       a[0], a[1], a[2], a[3],
 
964
                                       a[4], a[5], a[6], a[7],
 
965
                                       a[8], a[9], a[10], a[11],
 
966
                                       a[12], a[13], a[14], a[15]);
 
967
        else
 
968
            strpool = rk_strpoolprintf(strpool,
 
969
                                       "unknown IP address of length %lu",
 
970
                                       (unsigned long)name->u.iPAddress.length);
 
971
        break;
 
972
    }
 
973
    case choice_GeneralName_registeredID: {
 
974
        char *str;
 
975
        hx509_oid_sprint(&name->u.registeredID, &str);
 
976
        if (str == NULL)
 
977
            return ENOMEM;
 
978
        strpool = rk_strpoolprintf(strpool, "registeredID: %s", str);
 
979
        free(str);
 
980
        break;
 
981
    }
 
982
    default:
 
983
        return EINVAL;
 
984
    }
 
985
    if (strpool == NULL)
 
986
        return ENOMEM;
 
987
 
 
988
    *str = rk_strpoolcollect(strpool);
 
989
 
 
990
    return 0;
 
991
}