Coverage Report

Created: 2024-11-21 07:03

/src/nss-nspr/nss/lib/certdb/alg1485.c
Line
Count
Source (jump to first uncovered line)
1
/* alg1485.c - implementation of RFCs 1485, 1779 and 2253.
2
 *
3
 * This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include <limits.h>
8
#include "prprf.h"
9
#include "cert.h"
10
#include "certi.h"
11
#include "xconst.h"
12
#include "genname.h"
13
#include "secitem.h"
14
#include "secerr.h"
15
16
typedef struct NameToKindStr {
17
    const char* name;
18
    unsigned int maxLen; /* max bytes in UTF8 encoded string value */
19
    SECOidTag kind;
20
    int valueType;
21
} NameToKind;
22
23
/* local type for directory string--could be printable_string or utf8 */
24
0
#define SEC_ASN1_DS SEC_ASN1_HIGH_TAG_NUMBER
25
26
/* clang-format off */
27
28
/* Add new entries to this table, and maybe to function ParseRFC1485AVA */
29
static const NameToKind name2kinds[] = {
30
/* IANA registered type names
31
 * (See: http://www.iana.org/assignments/ldap-parameters)
32
 */
33
/* RFC 3280, 4630 MUST SUPPORT */
34
    { "CN",            640, SEC_OID_AVA_COMMON_NAME,    SEC_ASN1_DS},
35
    { "ST",            128, SEC_OID_AVA_STATE_OR_PROVINCE,
36
                                                        SEC_ASN1_DS},
37
    { "O",             128, SEC_OID_AVA_ORGANIZATION_NAME,
38
                                                        SEC_ASN1_DS},
39
    { "OU",            128, SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME,
40
                                                        SEC_ASN1_DS},
41
    { "dnQualifier", 32767, SEC_OID_AVA_DN_QUALIFIER, SEC_ASN1_PRINTABLE_STRING},
42
    { "C",               2, SEC_OID_AVA_COUNTRY_NAME, SEC_ASN1_PRINTABLE_STRING},
43
    { "serialNumber",   64, SEC_OID_AVA_SERIAL_NUMBER,SEC_ASN1_PRINTABLE_STRING},
44
45
/* RFC 3280, 4630 SHOULD SUPPORT */
46
    { "L",             128, SEC_OID_AVA_LOCALITY,       SEC_ASN1_DS},
47
    { "title",          64, SEC_OID_AVA_TITLE,          SEC_ASN1_DS},
48
    { "SN",             64, SEC_OID_AVA_SURNAME,        SEC_ASN1_DS},
49
    { "givenName",      64, SEC_OID_AVA_GIVEN_NAME,     SEC_ASN1_DS},
50
    { "initials",       64, SEC_OID_AVA_INITIALS,       SEC_ASN1_DS},
51
    { "generationQualifier",
52
                        64, SEC_OID_AVA_GENERATION_QUALIFIER,
53
                                                        SEC_ASN1_DS},
54
/* RFC 3280, 4630 MAY SUPPORT */
55
    { "DC",            128, SEC_OID_AVA_DC,             SEC_ASN1_IA5_STRING},
56
    { "MAIL",          256, SEC_OID_RFC1274_MAIL,       SEC_ASN1_IA5_STRING},
57
    { "UID",           256, SEC_OID_RFC1274_UID,        SEC_ASN1_DS},
58
59
/* ------------------ "strict" boundary ---------------------------------
60
 * In strict mode, cert_NameToAscii does not encode any of the attributes
61
 * below this line. The first SECOidTag below this line must be used to
62
 * conditionally define the "endKind" in function AppendAVA() below.
63
 * Most new attribute names should be added below this line.
64
 * Maybe this line should be up higher?  Say, after the 3280 MUSTs and
65
 * before the 3280 SHOULDs?
66
 */
67
68
/* values from draft-ietf-ldapbis-user-schema-05 (not in RFC 3280) */
69
    { "postalAddress", 128, SEC_OID_AVA_POSTAL_ADDRESS, SEC_ASN1_DS},
70
    { "postalCode",     40, SEC_OID_AVA_POSTAL_CODE,    SEC_ASN1_DS},
71
    { "postOfficeBox",  40, SEC_OID_AVA_POST_OFFICE_BOX,SEC_ASN1_DS},
72
    { "houseIdentifier",64, SEC_OID_AVA_HOUSE_IDENTIFIER,SEC_ASN1_DS},
73
/* end of IANA registered type names */
74
75
/* legacy keywords */
76
    { "E",             128, SEC_OID_PKCS9_EMAIL_ADDRESS,SEC_ASN1_IA5_STRING},
77
    { "STREET",        128, SEC_OID_AVA_STREET_ADDRESS, SEC_ASN1_DS},
78
    { "pseudonym",      64, SEC_OID_AVA_PSEUDONYM,      SEC_ASN1_DS},
79
80
/* values defined by the CAB Forum for EV */
81
    { "incorporationLocality", 128, SEC_OID_EV_INCORPORATION_LOCALITY,
82
                                    SEC_ASN1_DS},
83
    { "incorporationState",    128, SEC_OID_EV_INCORPORATION_STATE,
84
                                    SEC_ASN1_DS},
85
    { "incorporationCountry",    2, SEC_OID_EV_INCORPORATION_COUNTRY,
86
                                    SEC_ASN1_PRINTABLE_STRING},
87
    { "businessCategory",       64, SEC_OID_BUSINESS_CATEGORY, SEC_ASN1_DS},
88
89
/* values defined in X.520 */
90
    { "name",           64, SEC_OID_AVA_NAME,           SEC_ASN1_DS},
91
92
    { 0,               256, SEC_OID_UNKNOWN,            0},
93
};
94
95
/* Table facilitates conversion of ASCII hex to binary. */
96
static const PRInt16 x2b[256] = {
97
/* #0x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
98
/* #1x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
99
/* #2x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
100
/* #3x */  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
101
/* #4x */ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
102
/* #5x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
103
/* #6x */ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
104
/* #7x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
105
/* #8x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
106
/* #9x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
107
/* #ax */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
108
/* #bx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
109
/* #cx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
110
/* #dx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
111
/* #ex */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
112
/* #fx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
113
};
114
115
0
#define IS_HEX(c) (x2b[(PRUint8)(c)] >= 0)
116
117
0
#define C_DOUBLE_QUOTE '\042'
118
119
0
#define C_BACKSLASH '\134'
120
121
0
#define C_EQUAL '='
122
123
#define OPTIONAL_SPACE(c)                                                      \
124
0
    (((c) == ' ') || ((c) == '\r') || ((c) == '\n'))
125
126
#define SPECIAL_CHAR(c)                                                        \
127
0
    (((c) == ',') || ((c) == '=') || ((c) == C_DOUBLE_QUOTE) ||                \
128
0
     ((c) == '\r') || ((c) == '\n') || ((c) == '+') ||                         \
129
0
     ((c) == '<') || ((c) == '>') || ((c) == '#') ||                           \
130
0
     ((c) == ';') || ((c) == C_BACKSLASH))
131
132
133
#define IS_PRINTABLE(c)                                                        \
134
0
    ((((c) >= 'a') && ((c) <= 'z')) ||                                         \
135
0
     (((c) >= 'A') && ((c) <= 'Z')) ||                                         \
136
0
     (((c) >= '0') && ((c) <= '9')) ||                                         \
137
0
     ((c) == ' ') ||                                                           \
138
0
     ((c) == '\'') ||                                                          \
139
0
     ((c) == '\050') ||                     /* ( */                            \
140
0
     ((c) == '\051') ||                     /* ) */                            \
141
0
     (((c) >= '+') && ((c) <= '/')) ||      /* + , - . / */                    \
142
0
     ((c) == ':') ||                                                           \
143
0
     ((c) == '=') ||                                                           \
144
0
     ((c) == '?'))
145
146
/* clang-format on */
147
148
/* RFC 2253 says we must escape ",+\"\\<>;=" EXCEPT inside a quoted string.
149
 * Inside a quoted string, we only need to escape " and \
150
 * We choose to quote strings containing any of those special characters,
151
 * so we only need to escape " and \
152
 */
153
0
#define NEEDS_ESCAPE(c) (c == C_DOUBLE_QUOTE || c == C_BACKSLASH)
154
155
0
#define NEEDS_HEX_ESCAPE(c) ((PRUint8)c < 0x20 || c == 0x7f)
156
157
int
158
cert_AVAOidTagToMaxLen(SECOidTag tag)
159
0
{
160
0
    const NameToKind* n2k = name2kinds;
161
162
0
    while (n2k->kind != tag && n2k->kind != SEC_OID_UNKNOWN) {
163
0
        ++n2k;
164
0
    }
165
0
    return (n2k->kind != SEC_OID_UNKNOWN) ? n2k->maxLen : -1;
166
0
}
167
168
static PRBool
169
IsPrintable(unsigned char* data, unsigned len)
170
0
{
171
0
    unsigned char ch, *end;
172
173
0
    end = data + len;
174
0
    while (data < end) {
175
0
        ch = *data++;
176
0
        if (!IS_PRINTABLE(ch)) {
177
0
            return PR_FALSE;
178
0
        }
179
0
    }
180
0
    return PR_TRUE;
181
0
}
182
183
static void
184
skipSpace(const char** pbp, const char* endptr)
185
0
{
186
0
    const char* bp = *pbp;
187
0
    while (bp < endptr && OPTIONAL_SPACE(*bp)) {
188
0
        bp++;
189
0
    }
190
0
    *pbp = bp;
191
0
}
192
193
static SECStatus
194
scanTag(const char** pbp, const char* endptr, char* tagBuf, int tagBufSize)
195
0
{
196
0
    const char* bp;
197
0
    char* tagBufp;
198
0
    int taglen;
199
200
0
    PORT_Assert(tagBufSize > 0);
201
202
    /* skip optional leading space */
203
0
    skipSpace(pbp, endptr);
204
0
    if (*pbp == endptr) {
205
        /* nothing left */
206
0
        return SECFailure;
207
0
    }
208
209
    /* fill tagBuf */
210
0
    taglen = 0;
211
0
    bp = *pbp;
212
0
    tagBufp = tagBuf;
213
0
    while (bp < endptr && !OPTIONAL_SPACE(*bp) && (*bp != C_EQUAL)) {
214
0
        if (++taglen >= tagBufSize) {
215
0
            *pbp = bp;
216
0
            return SECFailure;
217
0
        }
218
0
        *tagBufp++ = *bp++;
219
0
    }
220
    /* null-terminate tagBuf -- guaranteed at least one space left */
221
0
    *tagBufp++ = 0;
222
0
    *pbp = bp;
223
224
    /* skip trailing spaces till we hit something - should be an equal sign */
225
0
    skipSpace(pbp, endptr);
226
0
    if (*pbp == endptr) {
227
        /* nothing left */
228
0
        return SECFailure;
229
0
    }
230
0
    if (**pbp != C_EQUAL) {
231
        /* should be an equal sign */
232
0
        return SECFailure;
233
0
    }
234
    /* skip over the equal sign */
235
0
    (*pbp)++;
236
237
0
    return SECSuccess;
238
0
}
239
240
/* Returns the number of bytes in the value. 0 means failure. */
241
static int
242
scanVal(const char** pbp, const char* endptr, char* valBuf, int valBufSize)
243
0
{
244
0
    const char* bp;
245
0
    char* valBufp;
246
0
    int vallen = 0;
247
0
    PRBool isQuoted;
248
249
0
    PORT_Assert(valBufSize > 0);
250
251
    /* skip optional leading space */
252
0
    skipSpace(pbp, endptr);
253
0
    if (*pbp == endptr) {
254
        /* nothing left */
255
0
        return 0;
256
0
    }
257
258
0
    bp = *pbp;
259
260
    /* quoted? */
261
0
    if (*bp == C_DOUBLE_QUOTE) {
262
0
        isQuoted = PR_TRUE;
263
        /* skip over it */
264
0
        bp++;
265
0
    } else {
266
0
        isQuoted = PR_FALSE;
267
0
    }
268
269
0
    valBufp = valBuf;
270
0
    while (bp < endptr) {
271
0
        char c = *bp;
272
0
        if (c == C_BACKSLASH) {
273
            /* escape character */
274
0
            bp++;
275
0
            if (bp >= endptr) {
276
                /* escape charater must appear with paired char */
277
0
                *pbp = bp;
278
0
                return 0;
279
0
            }
280
0
            c = *bp;
281
0
            if (IS_HEX(c) && (endptr - bp) >= 2 && IS_HEX(bp[1])) {
282
0
                bp++;
283
0
                c = (char)((x2b[(PRUint8)c] << 4) | x2b[(PRUint8)*bp]);
284
0
            }
285
0
        } else if (c == '#' && bp == *pbp) {
286
            /* ignore leading #, quotation not required for it. */
287
0
        } else if (!isQuoted && SPECIAL_CHAR(c)) {
288
            /* unescaped special and not within quoted value */
289
0
            break;
290
0
        } else if (c == C_DOUBLE_QUOTE) {
291
            /* reached unescaped double quote */
292
0
            break;
293
0
        }
294
        /* append character */
295
0
        vallen++;
296
0
        if (vallen >= valBufSize) {
297
0
            *pbp = bp;
298
0
            return 0;
299
0
        }
300
0
        *valBufp++ = c;
301
0
        bp++;
302
0
    }
303
304
    /* strip trailing spaces from unquoted values */
305
0
    if (!isQuoted) {
306
0
        while (valBufp > valBuf) {
307
0
            char c = valBufp[-1];
308
0
            if (!OPTIONAL_SPACE(c))
309
0
                break;
310
0
            --valBufp;
311
0
        }
312
0
        vallen = valBufp - valBuf;
313
0
    }
314
315
0
    if (isQuoted) {
316
        /* insist that we stopped on a double quote */
317
0
        if (*bp != C_DOUBLE_QUOTE) {
318
0
            *pbp = bp;
319
0
            return 0;
320
0
        }
321
        /* skip over the quote and skip optional space */
322
0
        bp++;
323
0
        skipSpace(&bp, endptr);
324
0
    }
325
326
0
    *pbp = bp;
327
328
    /* null-terminate valBuf -- guaranteed at least one space left */
329
0
    *valBufp = 0;
330
331
0
    return vallen;
332
0
}
333
334
/* Caller must set error code upon failure */
335
static SECStatus
336
hexToBin(PLArenaPool* pool, SECItem* destItem, const char* src, int len)
337
0
{
338
0
    PRUint8* dest;
339
340
0
    destItem->data = NULL;
341
0
    if (len <= 0 || (len & 1)) {
342
0
        goto loser;
343
0
    }
344
0
    len >>= 1;
345
0
    if (!SECITEM_AllocItem(pool, destItem, len)) {
346
0
        goto loser;
347
0
    }
348
0
    dest = destItem->data;
349
0
    for (; len > 0; len--, src += 2) {
350
0
        PRUint16 bin = ((PRUint16)x2b[(PRUint8)src[0]] << 4);
351
0
        bin |= (PRUint16)x2b[(PRUint8)src[1]];
352
0
        if (bin >> 15) { /* is negative */
353
0
            goto loser;
354
0
        }
355
0
        *dest++ = (PRUint8)bin;
356
0
    }
357
0
    return SECSuccess;
358
0
loser:
359
0
    if (!pool)
360
0
        SECITEM_FreeItem(destItem, PR_FALSE);
361
0
    return SECFailure;
362
0
}
363
364
/* Parses one AVA, starting at *pbp.  Stops at endptr.
365
 * Advances *pbp past parsed AVA and trailing separator (if present).
366
 * On any error, returns NULL and *pbp is undefined.
367
 * On success, returns CERTAVA allocated from arena, and (*pbp)[-1] was
368
 * the last character parsed.  *pbp is either equal to endptr or
369
 * points to first character after separator.
370
 */
371
static CERTAVA*
372
ParseRFC1485AVA(PLArenaPool* arena, const char** pbp, const char* endptr)
373
0
{
374
0
    CERTAVA* a;
375
0
    const NameToKind* n2k;
376
0
    const char* bp;
377
0
    int vt = -1;
378
0
    int valLen;
379
0
    PRBool isDottedOid = PR_FALSE;
380
0
    SECOidTag kind = SEC_OID_UNKNOWN;
381
0
    SECStatus rv = SECFailure;
382
0
    SECItem derOid = { 0, NULL, 0 };
383
0
    SECItem derVal = { 0, NULL, 0 };
384
0
    char sep = 0;
385
386
0
    char tagBuf[32];
387
0
    char valBuf[1024];
388
389
0
    PORT_Assert(arena);
390
0
    if (SECSuccess != scanTag(pbp, endptr, tagBuf, sizeof tagBuf) ||
391
0
        !(valLen = scanVal(pbp, endptr, valBuf, sizeof valBuf))) {
392
0
        goto loser;
393
0
    }
394
395
0
    bp = *pbp;
396
0
    if (bp < endptr) {
397
0
        sep = *bp++; /* skip over separator */
398
0
    }
399
0
    *pbp = bp;
400
    /* if we haven't finished, insist that we've stopped on a separator */
401
0
    if (sep && sep != ',' && sep != ';' && sep != '+') {
402
0
        goto loser;
403
0
    }
404
405
    /* is this a dotted decimal OID attribute type ? */
406
0
    if (!PL_strncasecmp("oid.", tagBuf, 4) || isdigit((unsigned char)tagBuf[0])) {
407
0
        rv = SEC_StringToOID(arena, &derOid, tagBuf, strlen(tagBuf));
408
0
        isDottedOid = (PRBool)(rv == SECSuccess);
409
0
    } else {
410
0
        for (n2k = name2kinds; n2k->name; n2k++) {
411
0
            SECOidData* oidrec;
412
0
            if (PORT_Strcasecmp(n2k->name, tagBuf) == 0) {
413
0
                kind = n2k->kind;
414
0
                vt = n2k->valueType;
415
0
                oidrec = SECOID_FindOIDByTag(kind);
416
0
                if (oidrec == NULL)
417
0
                    goto loser;
418
0
                derOid = oidrec->oid;
419
0
                break;
420
0
            }
421
0
        }
422
0
    }
423
0
    if (kind == SEC_OID_UNKNOWN && rv != SECSuccess)
424
0
        goto loser;
425
426
    /* Is this a hex encoding of a DER attribute value ? */
427
0
    if ('#' == valBuf[0]) {
428
        /* convert attribute value from hex to binary */
429
0
        rv = hexToBin(arena, &derVal, valBuf + 1, valLen - 1);
430
0
        if (rv)
431
0
            goto loser;
432
0
        a = CERT_CreateAVAFromRaw(arena, &derOid, &derVal);
433
0
    } else {
434
0
        if (kind == SEC_OID_AVA_COUNTRY_NAME && valLen != 2)
435
0
            goto loser;
436
0
        if (vt == SEC_ASN1_PRINTABLE_STRING &&
437
0
            !IsPrintable((unsigned char*)valBuf, valLen))
438
0
            goto loser;
439
0
        if (vt == SEC_ASN1_DS) {
440
            /* RFC 4630: choose PrintableString or UTF8String */
441
0
            if (IsPrintable((unsigned char*)valBuf, valLen))
442
0
                vt = SEC_ASN1_PRINTABLE_STRING;
443
0
            else
444
0
                vt = SEC_ASN1_UTF8_STRING;
445
0
        }
446
447
0
        derVal.data = (unsigned char*)valBuf;
448
0
        derVal.len = valLen;
449
0
        if (kind == SEC_OID_UNKNOWN && isDottedOid) {
450
0
            a = CERT_CreateAVAFromRaw(arena, &derOid, &derVal);
451
0
        } else {
452
0
            a = CERT_CreateAVAFromSECItem(arena, kind, vt, &derVal);
453
0
        }
454
0
    }
455
0
    return a;
456
457
0
loser:
458
    /* matched no kind -- invalid tag */
459
0
    PORT_SetError(SEC_ERROR_INVALID_AVA);
460
0
    return 0;
461
0
}
462
463
static CERTName*
464
ParseRFC1485Name(const char* buf, int len)
465
0
{
466
0
    SECStatus rv;
467
0
    CERTName* name;
468
0
    const char *bp, *e;
469
0
    CERTAVA* ava;
470
0
    CERTRDN* rdn = NULL;
471
472
0
    name = CERT_CreateName(NULL);
473
0
    if (name == NULL) {
474
0
        return NULL;
475
0
    }
476
477
0
    e = buf + len;
478
0
    bp = buf;
479
0
    while (bp < e) {
480
0
        ava = ParseRFC1485AVA(name->arena, &bp, e);
481
0
        if (ava == 0)
482
0
            goto loser;
483
0
        if (!rdn) {
484
0
            rdn = CERT_CreateRDN(name->arena, ava, (CERTAVA*)0);
485
0
            if (rdn == 0)
486
0
                goto loser;
487
0
            rv = CERT_AddRDN(name, rdn);
488
0
        } else {
489
0
            rv = CERT_AddAVA(name->arena, rdn, ava);
490
0
        }
491
0
        if (rv)
492
0
            goto loser;
493
0
        if (bp[-1] != '+')
494
0
            rdn = NULL; /* done with this RDN */
495
0
        skipSpace(&bp, e);
496
0
    }
497
498
0
    if (name->rdns[0] == 0) {
499
        /* empty name -- illegal */
500
0
        goto loser;
501
0
    }
502
503
    /* Reverse order of RDNS to comply with RFC */
504
0
    {
505
0
        CERTRDN** firstRdn;
506
0
        CERTRDN** lastRdn;
507
0
        CERTRDN* tmp;
508
509
        /* get first one */
510
0
        firstRdn = name->rdns;
511
512
        /* find last one */
513
0
        lastRdn = name->rdns;
514
0
        while (*lastRdn)
515
0
            lastRdn++;
516
0
        lastRdn--;
517
518
        /* reverse list */
519
0
        for (; firstRdn < lastRdn; firstRdn++, lastRdn--) {
520
0
            tmp = *firstRdn;
521
0
            *firstRdn = *lastRdn;
522
0
            *lastRdn = tmp;
523
0
        }
524
0
    }
525
526
    /* return result */
527
0
    return name;
528
529
0
loser:
530
0
    CERT_DestroyName(name);
531
0
    return NULL;
532
0
}
533
534
CERTName*
535
CERT_AsciiToName(const char* string)
536
0
{
537
0
    CERTName* name;
538
0
    name = ParseRFC1485Name(string, PORT_Strlen(string));
539
0
    return name;
540
0
}
541
542
/************************************************************************/
543
544
typedef struct stringBufStr {
545
    char* buffer;
546
    unsigned offset;
547
    unsigned size;
548
} stringBuf;
549
550
#define DEFAULT_BUFFER_SIZE 200
551
552
static SECStatus
553
AppendStr(stringBuf* bufp, char* str)
554
0
{
555
0
    char* buf;
556
0
    unsigned bufLen, bufSize, len;
557
0
    int size = 0;
558
559
    /* Figure out how much to grow buf by (add in the '\0') */
560
0
    buf = bufp->buffer;
561
0
    bufLen = bufp->offset;
562
0
    len = PORT_Strlen(str);
563
0
    bufSize = bufLen + len;
564
0
    if (!buf) {
565
0
        bufSize++;
566
0
        size = PR_MAX(DEFAULT_BUFFER_SIZE, bufSize * 2);
567
0
        buf = (char*)PORT_Alloc(size);
568
0
        bufp->size = size;
569
0
    } else if (bufp->size < bufSize) {
570
0
        size = bufSize * 2;
571
0
        buf = (char*)PORT_Realloc(buf, size);
572
0
        bufp->size = size;
573
0
    }
574
0
    if (!buf) {
575
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
576
0
        return SECFailure;
577
0
    }
578
0
    bufp->buffer = buf;
579
0
    bufp->offset = bufSize;
580
581
    /* Concatenate str onto buf */
582
0
    buf = buf + bufLen;
583
0
    if (bufLen)
584
0
        buf--;                      /* stomp on old '\0' */
585
0
    PORT_Memcpy(buf, str, len + 1); /* put in new null */
586
0
    return SECSuccess;
587
0
}
588
589
typedef enum {
590
    minimalEscape = 0,     /* only hex escapes, and " and \ */
591
    minimalEscapeAndQuote, /* as above, plus quoting        */
592
    fullEscape             /* no quoting, full escaping     */
593
} EQMode;
594
595
/* Some characters must be escaped as a hex string, e.g. c -> \nn .
596
 * Others must be escaped by preceding with a '\', e.g. c -> \c , but
597
 * there are certain "special characters" that may be handled by either
598
 * escaping them, or by enclosing the entire attribute value in quotes.
599
 * A NULL value for pEQMode implies selecting minimalEscape mode.
600
 * Some callers will do quoting when needed, others will not.
601
 * If a caller selects minimalEscapeAndQuote, and the string does not
602
 * need quoting, then this function changes it to minimalEscape.
603
 * Limit source to 16K, which avoids any possibility of overflow.
604
 * Maximum output size would be 3*srclen+2.
605
 */
606
static int
607
cert_RFC1485_GetRequiredLen(const char* src, int srclen, EQMode* pEQMode)
608
0
{
609
0
    int i, reqLen = 0;
610
0
    EQMode mode = pEQMode ? *pEQMode : minimalEscape;
611
0
    PRBool needsQuoting = PR_FALSE;
612
0
    char lastC = 0;
613
614
    /* avoids needing to check for overflow */
615
0
    if (srclen > 16384) {
616
0
        return -1;
617
0
    }
618
    /* need to make an initial pass to determine if quoting is needed */
619
0
    for (i = 0; i < srclen; i++) {
620
0
        char c = src[i];
621
0
        reqLen++;
622
0
        if (NEEDS_HEX_ESCAPE(c)) { /* c -> \xx  */
623
0
            reqLen += 2;
624
0
        } else if (NEEDS_ESCAPE(c)) { /* c -> \c   */
625
0
            reqLen++;
626
0
        } else if (SPECIAL_CHAR(c)) {
627
0
            if (mode == minimalEscapeAndQuote) /* quoting is allowed */
628
0
                needsQuoting = PR_TRUE;        /* entirety will need quoting */
629
0
            else if (mode == fullEscape)
630
0
                reqLen++; /* MAY escape this character */
631
0
        } else if (OPTIONAL_SPACE(c) && OPTIONAL_SPACE(lastC)) {
632
0
            if (mode == minimalEscapeAndQuote) /* quoting is allowed */
633
0
                needsQuoting = PR_TRUE;        /* entirety will need quoting */
634
0
        }
635
0
        lastC = c;
636
0
    }
637
    /* if it begins or ends in optional space it needs quoting */
638
0
    if (!needsQuoting && srclen > 0 && mode == minimalEscapeAndQuote &&
639
0
        (OPTIONAL_SPACE(src[srclen - 1]) || OPTIONAL_SPACE(src[0]))) {
640
0
        needsQuoting = PR_TRUE;
641
0
    }
642
643
0
    if (needsQuoting)
644
0
        reqLen += 2;
645
0
    if (pEQMode && mode == minimalEscapeAndQuote && !needsQuoting)
646
0
        *pEQMode = minimalEscape;
647
    /* Maximum output size would be 3*srclen+2 */
648
0
    return reqLen;
649
0
}
650
651
static const char hexChars[16] = { "0123456789abcdef" };
652
653
static SECStatus
654
escapeAndQuote(char* dst, int dstlen, char* src, int srclen, EQMode* pEQMode)
655
0
{
656
0
    int i, reqLen = 0;
657
0
    EQMode mode = pEQMode ? *pEQMode : minimalEscape;
658
659
0
    reqLen = cert_RFC1485_GetRequiredLen(src, srclen, &mode);
660
    /* reqLen is max 16384*3 + 2 */
661
    /* space for terminal null */
662
0
    if (reqLen < 0 || reqLen + 1 > dstlen) {
663
0
        PORT_SetError(SEC_ERROR_OUTPUT_LEN);
664
0
        return SECFailure;
665
0
    }
666
667
0
    if (mode == minimalEscapeAndQuote)
668
0
        *dst++ = C_DOUBLE_QUOTE;
669
0
    for (i = 0; i < srclen; i++) {
670
0
        char c = src[i];
671
0
        if (NEEDS_HEX_ESCAPE(c)) {
672
0
            *dst++ = C_BACKSLASH;
673
0
            *dst++ = hexChars[(c >> 4) & 0x0f];
674
0
            *dst++ = hexChars[c & 0x0f];
675
0
        } else {
676
0
            if (NEEDS_ESCAPE(c) || (SPECIAL_CHAR(c) && mode == fullEscape)) {
677
0
                *dst++ = C_BACKSLASH;
678
0
            }
679
0
            *dst++ = c;
680
0
        }
681
0
    }
682
0
    if (mode == minimalEscapeAndQuote)
683
0
        *dst++ = C_DOUBLE_QUOTE;
684
0
    *dst++ = 0;
685
0
    if (pEQMode)
686
0
        *pEQMode = mode;
687
0
    return SECSuccess;
688
0
}
689
690
SECStatus
691
CERT_RFC1485_EscapeAndQuote(char* dst, int dstlen, char* src, int srclen)
692
0
{
693
0
    EQMode mode = minimalEscapeAndQuote;
694
0
    return escapeAndQuote(dst, dstlen, src, srclen, &mode);
695
0
}
696
697
/* convert an OID to dotted-decimal representation */
698
/* Returns a string that must be freed with PR_smprintf_free(), */
699
char*
700
CERT_GetOidString(const SECItem* oid)
701
0
{
702
0
    PRUint8* stop;  /* points to first byte after OID string */
703
0
    PRUint8* first; /* byte of an OID component integer      */
704
0
    PRUint8* last;  /* byte of an OID component integer      */
705
0
    char* rvString = NULL;
706
0
    char* prefix = NULL;
707
708
0
#define MAX_OID_LEN 1024 /* bytes */
709
710
0
    if (oid->len > MAX_OID_LEN) {
711
0
        PORT_SetError(SEC_ERROR_INPUT_LEN);
712
0
        return NULL;
713
0
    }
714
715
    /* If the OID has length 1, we bail. */
716
0
    if (oid->len < 2) {
717
0
        return NULL;
718
0
    }
719
720
    /* first will point to the next sequence of bytes to decode */
721
0
    first = (PRUint8*)oid->data;
722
    /* stop points to one past the legitimate data */
723
0
    stop = &first[oid->len];
724
725
    /*
726
     * Check for our pseudo-encoded single-digit OIDs
727
     */
728
0
    if ((*first == 0x80) && (2 == oid->len)) {
729
        /* Funky encoding.  The second byte is the number */
730
0
        rvString = PR_smprintf("%lu", (PRUint32)first[1]);
731
0
        if (!rvString) {
732
0
            PORT_SetError(SEC_ERROR_NO_MEMORY);
733
0
        }
734
0
        return rvString;
735
0
    }
736
737
0
    for (; first < stop; first = last + 1) {
738
0
        unsigned int bytesBeforeLast;
739
740
0
        for (last = first; last < stop; last++) {
741
0
            if (0 == (*last & 0x80)) {
742
0
                break;
743
0
            }
744
0
        }
745
        /* There's no first bit set, so this isn't valid. Bail.*/
746
0
        if (last == stop) {
747
0
            goto unsupported;
748
0
        }
749
0
        bytesBeforeLast = (unsigned int)(last - first);
750
0
        if (bytesBeforeLast <= 3U) { /* 0-28 bit number */
751
0
            PRUint32 n = 0;
752
0
            PRUint32 c;
753
754
0
#define CGET(i, m)    \
755
0
    c = last[-i] & m; \
756
0
    n |= c << (7 * i)
757
758
0
#define CASE(i, m)  \
759
0
    case i:         \
760
0
        CGET(i, m); \
761
0
        if (!n)     \
762
0
        goto unsupported /* fall-through */
763
764
0
            switch (bytesBeforeLast) {
765
0
                CASE(3, 0x7f);
766
0
                CASE(2, 0x7f);
767
0
                CASE(1, 0x7f);
768
0
                case 0:
769
0
                    n |= last[0] & 0x7f;
770
0
                    break;
771
0
            }
772
0
            if (last[0] & 0x80) {
773
0
                goto unsupported;
774
0
            }
775
776
0
            if (!rvString) {
777
                /* This is the first number.. decompose it */
778
0
                PRUint32 one = PR_MIN(n / 40, 2); /* never > 2 */
779
0
                PRUint32 two = n - (one * 40);
780
781
0
                rvString = PR_smprintf("OID.%lu.%lu", one, two);
782
0
            } else {
783
0
                prefix = rvString;
784
0
                rvString = PR_smprintf("%s.%lu", prefix, n);
785
0
            }
786
0
        } else if (bytesBeforeLast <= 9U) { /* 29-64 bit number */
787
0
            PRUint64 n = 0;
788
0
            PRUint64 c;
789
790
0
            switch (bytesBeforeLast) {
791
0
                CASE(9, 0x01);
792
0
                CASE(8, 0x7f);
793
0
                CASE(7, 0x7f);
794
0
                CASE(6, 0x7f);
795
0
                CASE(5, 0x7f);
796
0
                CASE(4, 0x7f);
797
0
                CGET(3, 0x7f);
798
0
                CGET(2, 0x7f);
799
0
                CGET(1, 0x7f);
800
0
                CGET(0, 0x7f);
801
0
                break;
802
0
            }
803
0
            if (last[0] & 0x80)
804
0
                goto unsupported;
805
806
0
            if (!rvString) {
807
                /* This is the first number.. decompose it */
808
0
                PRUint64 one = PR_MIN(n / 40, 2); /* never > 2 */
809
0
                PRUint64 two = n - (one * 40);
810
811
0
                rvString = PR_smprintf("OID.%llu.%llu", one, two);
812
0
            } else {
813
0
                prefix = rvString;
814
0
                rvString = PR_smprintf("%s.%llu", prefix, n);
815
0
            }
816
0
        } else {
817
        /* More than a 64-bit number, or not minimal encoding. */
818
0
        unsupported:
819
0
            if (!rvString)
820
0
                rvString = PR_smprintf("OID.UNSUPPORTED");
821
0
            else {
822
0
                prefix = rvString;
823
0
                rvString = PR_smprintf("%s.UNSUPPORTED", prefix);
824
0
            }
825
0
        }
826
827
0
        if (prefix) {
828
0
            PR_smprintf_free(prefix);
829
0
            prefix = NULL;
830
0
        }
831
0
        if (!rvString) {
832
0
            PORT_SetError(SEC_ERROR_NO_MEMORY);
833
0
            break;
834
0
        }
835
0
    }
836
0
    return rvString;
837
0
}
838
839
/* convert DER-encoded hex to a string */
840
static SECItem*
841
get_hex_string(SECItem* data)
842
0
{
843
0
    SECItem* rv;
844
0
    unsigned int i, j;
845
0
    static const char hex[] = { "0123456789ABCDEF" };
846
847
    /* '#' + 2 chars per octet + terminator */
848
0
    rv = SECITEM_AllocItem(NULL, NULL, data->len * 2 + 2);
849
0
    if (!rv) {
850
0
        return NULL;
851
0
    }
852
0
    rv->data[0] = '#';
853
0
    rv->len = 1 + 2 * data->len;
854
0
    for (i = 0; i < data->len; i++) {
855
0
        j = data->data[i];
856
0
        rv->data[2 * i + 1] = hex[j >> 4];
857
0
        rv->data[2 * i + 2] = hex[j & 15];
858
0
    }
859
0
    rv->data[rv->len] = 0;
860
0
    return rv;
861
0
}
862
863
/* For compliance with RFC 2253, RFC 3280 and RFC 4630, we choose to
864
 * use the NAME=STRING form, rather than the OID.N.N=#hexXXXX form,
865
 * when both of these conditions are met:
866
 *  1) The attribute name OID (kind) has a known name string that is
867
 *     defined in one of those RFCs, or in RFCs that they cite, AND
868
 *  2) The attribute's value encoding is RFC compliant for the kind
869
 *     (e.g., the value's encoding tag is correct for the kind, and
870
 *     the value's length is in the range allowed for the kind, and
871
 *     the value's contents are appropriate for the encoding tag).
872
 *  Otherwise, we use the OID.N.N=#hexXXXX form.
873
 *
874
 *  If the caller prefers maximum human readability to RFC compliance,
875
 *  then
876
 *  - We print the kind in NAME= string form if we know the name
877
 *    string for the attribute type OID, regardless of whether the
878
 *    value is correctly encoded or not. else we use the OID.N.N= form.
879
 *  - We use the non-hex STRING form for the attribute value if the
880
 *    value can be represented in such a form.  Otherwise, we use
881
 *    the hex string form.
882
 *  This implies that, for maximum human readability, in addition to
883
 *  the two forms allowed by the RFC, we allow two other forms of output:
884
 *  - the OID.N.N=STRING form, and
885
 *  - the NAME=#hexXXXX form
886
 *  When the caller prefers maximum human readability, we do not allow
887
 *  the value of any attribute to exceed the length allowed by the RFC.
888
 *  If the attribute value exceeds the allowed length, we truncate it to
889
 *  the allowed length and append "...".
890
 *  Also in this case, we arbitrarily impose a limit on the length of the
891
 *  entire AVA encoding, regardless of the form, of 384 bytes per AVA.
892
 *  This limit includes the trailing NULL character.  If the encoded
893
 *  AVA length exceeds that limit, this function reports failure to encode
894
 *  the AVA.
895
 *
896
 *  An ASCII representation of an AVA is said to be "invertible" if
897
 *  conversion back to DER reproduces the original DER encoding exactly.
898
 *  The RFC 2253 rules do not ensure that all ASCII AVAs derived according
899
 *  to its rules are invertible. That is because the RFCs allow some
900
 *  attribute values to be encoded in any of a number of encodings,
901
 *  and the encoding type information is lost in the non-hex STRING form.
902
 *  This is particularly true of attributes of type DirectoryString.
903
 *  The encoding type information is always preserved in the hex string
904
 *  form, because the hex includes the entire DER encoding of the value.
905
 *
906
 *  So, when the caller perfers maximum invertibility, we apply the
907
 *  RFC compliance rules stated above, and add a third required
908
 *  condition on the use of the NAME=STRING form.
909
 *   3) The attribute's kind is not is allowed to be encoded in any of
910
 *      several different encodings, such as DirectoryStrings.
911
 *
912
 * The chief difference between CERT_N2A_STRICT and CERT_N2A_INVERTIBLE
913
 * is that the latter forces DirectoryStrings to be hex encoded.
914
 *
915
 * As a simplification, we assume the value is correctly encoded for
916
 * its encoding type.  That is, we do not test that all the characters
917
 * in a string encoded type are allowed by that type.  We assume it.
918
 */
919
static SECStatus
920
AppendAVA(stringBuf* bufp, CERTAVA* ava, CertStrictnessLevel strict)
921
0
{
922
0
#define TMPBUF_LEN 2048
923
0
    const NameToKind* pn2k = name2kinds;
924
0
    SECItem* avaValue = NULL;
925
0
    char* unknownTag = NULL;
926
0
    char* encodedAVA = NULL;
927
0
    PRBool useHex = PR_FALSE; /* use =#hexXXXX form */
928
0
    PRBool truncateName = PR_FALSE;
929
0
    PRBool truncateValue = PR_FALSE;
930
0
    SECOidTag endKind;
931
0
    SECStatus rv;
932
0
    unsigned int len;
933
0
    unsigned int nameLen, valueLen;
934
0
    unsigned int maxName, maxValue;
935
0
    EQMode mode = minimalEscapeAndQuote;
936
0
    NameToKind n2k = { NULL, 32767, SEC_OID_UNKNOWN, SEC_ASN1_DS };
937
0
    char tmpBuf[TMPBUF_LEN];
938
939
0
#define tagName n2k.name /* non-NULL means use NAME= form */
940
0
#define maxBytes n2k.maxLen
941
0
#define tag n2k.kind
942
0
#define vt n2k.valueType
943
944
    /* READABLE mode recognizes more names from the name2kinds table
945
     * than do STRICT or INVERTIBLE modes.  This assignment chooses the
946
     * point in the table where the attribute type name scanning stops.
947
     */
948
0
    endKind = (strict == CERT_N2A_READABLE) ? SEC_OID_UNKNOWN
949
0
                                            : SEC_OID_AVA_POSTAL_ADDRESS;
950
0
    tag = CERT_GetAVATag(ava);
951
0
    while (pn2k->kind != tag && pn2k->kind != endKind) {
952
0
        ++pn2k;
953
0
    }
954
955
0
    if (pn2k->kind != endKind) {
956
0
        n2k = *pn2k;
957
0
    } else if (strict != CERT_N2A_READABLE) {
958
0
        useHex = PR_TRUE;
959
0
    }
960
    /* For invertable form, force Directory Strings to use hex form. */
961
0
    if (strict == CERT_N2A_INVERTIBLE && vt == SEC_ASN1_DS) {
962
0
        tagName = NULL;   /* must use OID.N form */
963
0
        useHex = PR_TRUE; /* must use hex string */
964
0
    }
965
0
    if (!useHex) {
966
0
        avaValue = CERT_DecodeAVAValue(&ava->value);
967
0
        if (!avaValue) {
968
0
            useHex = PR_TRUE;
969
0
            if (strict != CERT_N2A_READABLE) {
970
0
                tagName = NULL; /* must use OID.N form */
971
0
            }
972
0
        }
973
0
    }
974
0
    if (!tagName) {
975
        /* handle unknown attribute types per RFC 2253 */
976
0
        tagName = unknownTag = CERT_GetOidString(&ava->type);
977
0
        if (!tagName) {
978
0
            if (avaValue)
979
0
                SECITEM_FreeItem(avaValue, PR_TRUE);
980
0
            return SECFailure;
981
0
        }
982
0
    }
983
0
    if (useHex) {
984
0
        avaValue = get_hex_string(&ava->value);
985
0
        if (!avaValue) {
986
0
            if (unknownTag)
987
0
                PR_smprintf_free(unknownTag);
988
0
            return SECFailure;
989
0
        }
990
0
    }
991
992
0
    nameLen = strlen(tagName);
993
994
0
    if (useHex) {
995
0
        valueLen = avaValue->len;
996
0
    } else {
997
0
        int reqLen = cert_RFC1485_GetRequiredLen((char*)avaValue->data, avaValue->len, &mode);
998
0
        if (reqLen < 0) {
999
0
            SECITEM_FreeItem(avaValue, PR_TRUE);
1000
0
            return SECFailure;
1001
0
        }
1002
0
        valueLen = reqLen;
1003
0
    }
1004
0
    if (UINT_MAX - nameLen < 2 ||
1005
0
        valueLen > UINT_MAX - nameLen - 2) {
1006
0
        SECITEM_FreeItem(avaValue, PR_TRUE);
1007
0
        return SECFailure;
1008
0
    }
1009
0
    len = nameLen + valueLen + 2; /* Add 2 for '=' and trailing NUL */
1010
1011
0
    maxName = nameLen;
1012
0
    maxValue = valueLen;
1013
0
    if (len <= sizeof(tmpBuf)) {
1014
0
        encodedAVA = tmpBuf;
1015
0
    } else if (strict != CERT_N2A_READABLE) {
1016
0
        encodedAVA = PORT_Alloc(len);
1017
0
        if (!encodedAVA) {
1018
0
            SECITEM_FreeItem(avaValue, PR_TRUE);
1019
0
            if (unknownTag)
1020
0
                PR_smprintf_free(unknownTag);
1021
0
            return SECFailure;
1022
0
        }
1023
0
    } else {
1024
        /* Must make output fit in tmpbuf */
1025
0
        unsigned int fair = (sizeof tmpBuf) / 2 - 1; /* for = and \0 */
1026
1027
0
        if (nameLen < fair) {
1028
            /* just truncate the value */
1029
0
            maxValue = (sizeof tmpBuf) - (nameLen + 6); /* for "=...\0",
1030
                                                     and possibly '"' */
1031
0
        } else if (valueLen < fair) {
1032
            /* just truncate the name */
1033
0
            maxName = (sizeof tmpBuf) - (valueLen + 5); /* for "=...\0" */
1034
0
        } else {
1035
            /* truncate both */
1036
0
            maxName = maxValue = fair - 3; /* for "..." */
1037
0
        }
1038
0
        if (nameLen > maxName) {
1039
0
            PORT_Assert(unknownTag && unknownTag == tagName);
1040
0
            truncateName = PR_TRUE;
1041
0
            nameLen = maxName;
1042
0
        }
1043
0
        encodedAVA = tmpBuf;
1044
0
    }
1045
1046
0
    memcpy(encodedAVA, tagName, nameLen);
1047
0
    if (truncateName) {
1048
        /* If tag name is too long, we know it is an OID form that was
1049
         * allocated from the heap, so we can modify it in place
1050
         */
1051
0
        encodedAVA[nameLen - 1] = '.';
1052
0
        encodedAVA[nameLen - 2] = '.';
1053
0
        encodedAVA[nameLen - 3] = '.';
1054
0
    }
1055
0
    encodedAVA[nameLen++] = '=';
1056
0
    if (unknownTag)
1057
0
        PR_smprintf_free(unknownTag);
1058
1059
0
    if (strict == CERT_N2A_READABLE && maxValue > maxBytes)
1060
0
        maxValue = maxBytes;
1061
0
    if (valueLen > maxValue) {
1062
0
        valueLen = maxValue;
1063
0
        truncateValue = PR_TRUE;
1064
0
    }
1065
    /* escape and quote as necessary - don't quote hex strings */
1066
0
    if (useHex) {
1067
0
        char* end = encodedAVA + nameLen + valueLen;
1068
0
        memcpy(encodedAVA + nameLen, (char*)avaValue->data, valueLen);
1069
0
        end[0] = '\0';
1070
0
        if (truncateValue) {
1071
0
            end[-1] = '.';
1072
0
            end[-2] = '.';
1073
0
            end[-3] = '.';
1074
0
        }
1075
0
        rv = SECSuccess;
1076
0
    } else if (!truncateValue) {
1077
0
        rv = escapeAndQuote(encodedAVA + nameLen, len - nameLen,
1078
0
                            (char*)avaValue->data, avaValue->len, &mode);
1079
0
    } else {
1080
        /* must truncate the escaped and quoted value */
1081
0
        char bigTmpBuf[TMPBUF_LEN * 3 + 3];
1082
0
        PORT_Assert(valueLen < sizeof tmpBuf);
1083
0
        rv = escapeAndQuote(bigTmpBuf, sizeof bigTmpBuf, (char*)avaValue->data,
1084
0
                            PR_MIN(avaValue->len, valueLen), &mode);
1085
1086
0
        bigTmpBuf[valueLen--] = '\0'; /* hard stop here */
1087
        /* See if we're in the middle of a multi-byte UTF8 character */
1088
0
        while (((bigTmpBuf[valueLen] & 0xc0) == 0x80) && valueLen > 0) {
1089
0
            bigTmpBuf[valueLen--] = '\0';
1090
0
        }
1091
        /* add ellipsis to signify truncation. */
1092
0
        bigTmpBuf[++valueLen] = '.';
1093
0
        bigTmpBuf[++valueLen] = '.';
1094
0
        bigTmpBuf[++valueLen] = '.';
1095
0
        if (bigTmpBuf[0] == '"')
1096
0
            bigTmpBuf[++valueLen] = '"';
1097
0
        bigTmpBuf[++valueLen] = '\0';
1098
0
        PORT_Assert(nameLen + valueLen <= (sizeof tmpBuf) - 1);
1099
0
        memcpy(encodedAVA + nameLen, bigTmpBuf, valueLen + 1);
1100
0
    }
1101
1102
0
    SECITEM_FreeItem(avaValue, PR_TRUE);
1103
0
    if (rv == SECSuccess)
1104
0
        rv = AppendStr(bufp, encodedAVA);
1105
0
    if (encodedAVA != tmpBuf)
1106
0
        PORT_Free(encodedAVA);
1107
0
    return rv;
1108
0
}
1109
1110
#undef tagName
1111
#undef maxBytes
1112
#undef tag
1113
#undef vt
1114
1115
char*
1116
CERT_NameToAsciiInvertible(CERTName* name, CertStrictnessLevel strict)
1117
0
{
1118
0
    CERTRDN** rdns;
1119
0
    CERTRDN** lastRdn;
1120
0
    CERTRDN** rdn;
1121
0
    PRBool first = PR_TRUE;
1122
0
    stringBuf strBuf = { NULL, 0, 0 };
1123
1124
0
    rdns = name->rdns;
1125
0
    if (rdns == NULL) {
1126
0
        return NULL;
1127
0
    }
1128
1129
    /* find last RDN */
1130
0
    lastRdn = rdns;
1131
0
    while (*lastRdn)
1132
0
        lastRdn++;
1133
0
    lastRdn--;
1134
1135
    /*
1136
     * Loop over name contents in _reverse_ RDN order appending to string
1137
     */
1138
0
    for (rdn = lastRdn; rdn >= rdns; rdn--) {
1139
0
        CERTAVA** avas = (*rdn)->avas;
1140
0
        CERTAVA* ava;
1141
0
        PRBool newRDN = PR_TRUE;
1142
1143
        /*
1144
         * XXX Do we need to traverse the AVAs in reverse order, too?
1145
         */
1146
0
        while (avas && (ava = *avas++) != NULL) {
1147
0
            SECStatus rv;
1148
            /* Put in comma or plus separator */
1149
0
            if (!first) {
1150
                /* Use of spaces is deprecated in RFC 2253. */
1151
0
                rv = AppendStr(&strBuf, newRDN ? "," : "+");
1152
0
                if (rv)
1153
0
                    goto loser;
1154
0
            } else {
1155
0
                first = PR_FALSE;
1156
0
            }
1157
1158
            /* Add in tag type plus value into strBuf */
1159
0
            rv = AppendAVA(&strBuf, ava, strict);
1160
0
            if (rv)
1161
0
                goto loser;
1162
0
            newRDN = PR_FALSE;
1163
0
        }
1164
0
    }
1165
0
    return strBuf.buffer;
1166
0
loser:
1167
0
    if (strBuf.buffer) {
1168
0
        PORT_Free(strBuf.buffer);
1169
0
    }
1170
0
    return NULL;
1171
0
}
1172
1173
char*
1174
CERT_NameToAscii(CERTName* name)
1175
0
{
1176
0
    return CERT_NameToAsciiInvertible(name, CERT_N2A_READABLE);
1177
0
}
1178
1179
/*
1180
 * Return the string representation of a DER encoded distinguished name
1181
 * "dername" - The DER encoded name to convert
1182
 */
1183
char*
1184
CERT_DerNameToAscii(SECItem* dername)
1185
0
{
1186
0
    int rv;
1187
0
    PLArenaPool* arena = NULL;
1188
0
    CERTName name;
1189
0
    char* retstr = NULL;
1190
1191
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1192
1193
0
    if (arena == NULL) {
1194
0
        goto loser;
1195
0
    }
1196
1197
0
    rv = SEC_QuickDERDecodeItem(arena, &name, CERT_NameTemplate, dername);
1198
1199
0
    if (rv != SECSuccess) {
1200
0
        goto loser;
1201
0
    }
1202
1203
0
    retstr = CERT_NameToAscii(&name);
1204
1205
0
loser:
1206
0
    if (arena != NULL) {
1207
0
        PORT_FreeArena(arena, PR_FALSE);
1208
0
    }
1209
1210
0
    return (retstr);
1211
0
}
1212
1213
static char*
1214
avaToString(PLArenaPool* arena, CERTAVA* ava)
1215
0
{
1216
0
    char* buf = NULL;
1217
0
    SECItem* avaValue;
1218
0
    int valueLen;
1219
1220
0
    avaValue = CERT_DecodeAVAValue(&ava->value);
1221
0
    if (!avaValue) {
1222
0
        return buf;
1223
0
    }
1224
0
    int reqLen = cert_RFC1485_GetRequiredLen((char*)avaValue->data, avaValue->len, NULL);
1225
    /* reqLen is max 16384*3 + 2 */
1226
0
    if (reqLen >= 0) {
1227
0
        valueLen = reqLen + 1;
1228
0
        if (arena) {
1229
0
            buf = (char*)PORT_ArenaZAlloc(arena, valueLen);
1230
0
        } else {
1231
0
            buf = (char*)PORT_ZAlloc(valueLen);
1232
0
        }
1233
0
        if (buf) {
1234
0
            SECStatus rv =
1235
0
                escapeAndQuote(buf, valueLen, (char*)avaValue->data, avaValue->len, NULL);
1236
0
            if (rv != SECSuccess) {
1237
0
                if (!arena)
1238
0
                    PORT_Free(buf);
1239
0
                buf = NULL;
1240
0
            }
1241
0
        }
1242
0
    }
1243
0
    SECITEM_FreeItem(avaValue, PR_TRUE);
1244
0
    return buf;
1245
0
}
1246
1247
/* RDNs are sorted from most general to most specific.
1248
 * This code returns the FIRST one found, the most general one found.
1249
 */
1250
static char*
1251
CERT_GetNameElement(PLArenaPool* arena, const CERTName* name, int wantedTag)
1252
0
{
1253
0
    CERTRDN** rdns = name->rdns;
1254
0
    CERTRDN* rdn;
1255
0
    CERTAVA* ava = NULL;
1256
1257
0
    while (rdns && (rdn = *rdns++) != 0) {
1258
0
        CERTAVA** avas = rdn->avas;
1259
0
        while (avas && (ava = *avas++) != 0) {
1260
0
            int tag = CERT_GetAVATag(ava);
1261
0
            if (tag == wantedTag) {
1262
0
                avas = NULL;
1263
0
                rdns = NULL; /* break out of all loops */
1264
0
            }
1265
0
        }
1266
0
    }
1267
0
    return ava ? avaToString(arena, ava) : NULL;
1268
0
}
1269
1270
/* RDNs are sorted from most general to most specific.
1271
 * This code returns the LAST one found, the most specific one found.
1272
 * This is particularly appropriate for Common Name.  See RFC 2818.
1273
 */
1274
static char*
1275
CERT_GetLastNameElement(PLArenaPool* arena, const CERTName* name, int wantedTag)
1276
0
{
1277
0
    CERTRDN** rdns = name->rdns;
1278
0
    CERTRDN* rdn;
1279
0
    CERTAVA* lastAva = NULL;
1280
1281
0
    while (rdns && (rdn = *rdns++) != 0) {
1282
0
        CERTAVA** avas = rdn->avas;
1283
0
        CERTAVA* ava;
1284
0
        while (avas && (ava = *avas++) != 0) {
1285
0
            int tag = CERT_GetAVATag(ava);
1286
0
            if (tag == wantedTag) {
1287
0
                lastAva = ava;
1288
0
            }
1289
0
        }
1290
0
    }
1291
0
    return lastAva ? avaToString(arena, lastAva) : NULL;
1292
0
}
1293
1294
char*
1295
CERT_GetCertificateEmailAddress(CERTCertificate* cert)
1296
0
{
1297
0
    char* rawEmailAddr = NULL;
1298
0
    SECItem subAltName;
1299
0
    SECStatus rv;
1300
0
    CERTGeneralName* nameList = NULL;
1301
0
    CERTGeneralName* current;
1302
0
    PLArenaPool* arena = NULL;
1303
0
    int i;
1304
1305
0
    subAltName.data = NULL;
1306
1307
0
    rawEmailAddr = CERT_GetNameElement(cert->arena, &(cert->subject),
1308
0
                                       SEC_OID_PKCS9_EMAIL_ADDRESS);
1309
0
    if (rawEmailAddr == NULL) {
1310
0
        rawEmailAddr =
1311
0
            CERT_GetNameElement(cert->arena, &(cert->subject), SEC_OID_RFC1274_MAIL);
1312
0
    }
1313
0
    if (rawEmailAddr == NULL) {
1314
1315
0
        rv =
1316
0
            CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, &subAltName);
1317
0
        if (rv != SECSuccess) {
1318
0
            goto finish;
1319
0
        }
1320
0
        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1321
0
        if (!arena) {
1322
0
            goto finish;
1323
0
        }
1324
0
        nameList = current = CERT_DecodeAltNameExtension(arena, &subAltName);
1325
0
        if (!nameList) {
1326
0
            goto finish;
1327
0
        }
1328
0
        if (nameList != NULL) {
1329
0
            do {
1330
0
                if (current->type == certDirectoryName) {
1331
0
                    rawEmailAddr =
1332
0
                        CERT_GetNameElement(cert->arena, &(current->name.directoryName),
1333
0
                                            SEC_OID_PKCS9_EMAIL_ADDRESS);
1334
0
                    if (rawEmailAddr ==
1335
0
                        NULL) {
1336
0
                        rawEmailAddr =
1337
0
                            CERT_GetNameElement(cert->arena, &(current->name.directoryName),
1338
0
                                                SEC_OID_RFC1274_MAIL);
1339
0
                    }
1340
0
                } else if (current->type == certRFC822Name) {
1341
0
                    rawEmailAddr =
1342
0
                        (char*)PORT_ArenaZAlloc(cert->arena, current->name.other.len + 1);
1343
0
                    if (!rawEmailAddr) {
1344
0
                        goto finish;
1345
0
                    }
1346
0
                    PORT_Memcpy(rawEmailAddr, current->name.other.data,
1347
0
                                current->name.other.len);
1348
0
                    rawEmailAddr[current->name.other.len] =
1349
0
                        '\0';
1350
0
                }
1351
0
                if (rawEmailAddr) {
1352
0
                    break;
1353
0
                }
1354
0
                current = CERT_GetNextGeneralName(current);
1355
0
            } while (current != nameList);
1356
0
        }
1357
0
    }
1358
0
    if (rawEmailAddr) {
1359
0
        for (i = 0; i <= (int)PORT_Strlen(rawEmailAddr); i++) {
1360
0
            rawEmailAddr[i] = tolower((unsigned char)rawEmailAddr[i]);
1361
0
        }
1362
0
    }
1363
1364
0
finish:
1365
1366
    /* Don't free nameList, it's part of the arena. */
1367
1368
0
    if (arena) {
1369
0
        PORT_FreeArena(arena, PR_FALSE);
1370
0
    }
1371
1372
0
    if (subAltName.data) {
1373
0
        SECITEM_FreeItem(&subAltName, PR_FALSE);
1374
0
    }
1375
1376
0
    return (rawEmailAddr);
1377
0
}
1378
1379
static char*
1380
appendStringToBuf(char* dest, char* src, PRUint32* pRemaining)
1381
0
{
1382
0
    PRUint32 len;
1383
0
    if (dest && src && src[0] && *pRemaining > (len = PL_strlen(src))) {
1384
0
        PRUint32 i;
1385
0
        for (i = 0; i < len; ++i)
1386
0
            dest[i] = tolower((unsigned char)src[i]);
1387
0
        dest[len] = 0;
1388
0
        dest += len + 1;
1389
0
        *pRemaining -= len + 1;
1390
0
    }
1391
0
    return dest;
1392
0
}
1393
1394
#undef NEEDS_HEX_ESCAPE
1395
0
#define NEEDS_HEX_ESCAPE(c) (c < 0x20)
1396
1397
static char*
1398
appendItemToBuf(char* dest, SECItem* src, PRUint32* pRemaining)
1399
0
{
1400
0
    if (dest && src && src->data && src->len && src->data[0]) {
1401
0
        PRUint32 len = src->len;
1402
0
        PRUint32 i;
1403
0
        PRUint32 reqLen = len + 1;
1404
        /* are there any embedded control characters ? */
1405
0
        for (i = 0; i < len; i++) {
1406
0
            if (NEEDS_HEX_ESCAPE(src->data[i]))
1407
0
                reqLen += 2;
1408
0
        }
1409
0
        if (*pRemaining > reqLen) {
1410
0
            for (i = 0; i < len; ++i) {
1411
0
                PRUint8 c = src->data[i];
1412
0
                if (NEEDS_HEX_ESCAPE(c)) {
1413
0
                    *dest++ =
1414
0
                        C_BACKSLASH;
1415
0
                    *dest++ =
1416
0
                        hexChars[(c >> 4) & 0x0f];
1417
0
                    *dest++ =
1418
0
                        hexChars[c & 0x0f];
1419
0
                } else {
1420
0
                    *dest++ =
1421
0
                        tolower(c);
1422
0
                }
1423
0
            }
1424
0
            *dest++ = '\0';
1425
0
            *pRemaining -= reqLen;
1426
0
        }
1427
0
    }
1428
0
    return dest;
1429
0
}
1430
1431
/* Returns a pointer to an environment-like string, a series of
1432
** null-terminated strings, terminated by a zero-length string.
1433
** This function is intended to be internal to NSS.
1434
*/
1435
char*
1436
cert_GetCertificateEmailAddresses(CERTCertificate* cert)
1437
0
{
1438
0
    char* rawEmailAddr = NULL;
1439
0
    char* addrBuf = NULL;
1440
0
    char* pBuf = NULL;
1441
0
    PORTCheapArenaPool tmpArena;
1442
0
    PRUint32 maxLen = 0;
1443
0
    PRInt32 finalLen = 0;
1444
0
    SECStatus rv;
1445
0
    SECItem subAltName;
1446
1447
0
    PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
1448
1449
0
    subAltName.data = NULL;
1450
0
    maxLen = cert->derCert.len;
1451
0
    PORT_Assert(maxLen);
1452
0
    if (!maxLen)
1453
0
        maxLen = 2000; /* a guess, should never happen */
1454
1455
0
    pBuf = addrBuf = (char*)PORT_ArenaZAlloc(&tmpArena.arena, maxLen + 1);
1456
0
    if (!addrBuf)
1457
0
        goto loser;
1458
1459
0
    rawEmailAddr = CERT_GetNameElement(&tmpArena.arena, &cert->subject,
1460
0
                                       SEC_OID_PKCS9_EMAIL_ADDRESS);
1461
0
    pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
1462
1463
0
    rawEmailAddr = CERT_GetNameElement(&tmpArena.arena, &cert->subject,
1464
0
                                       SEC_OID_RFC1274_MAIL);
1465
0
    pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
1466
1467
0
    rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, &subAltName);
1468
0
    if (rv == SECSuccess && subAltName.data) {
1469
0
        CERTGeneralName* nameList = NULL;
1470
1471
0
        if (!!(nameList = CERT_DecodeAltNameExtension(&tmpArena.arena, &subAltName))) {
1472
0
            CERTGeneralName* current = nameList;
1473
0
            do {
1474
0
                if (current->type == certDirectoryName) {
1475
0
                    rawEmailAddr =
1476
0
                        CERT_GetNameElement(&tmpArena.arena,
1477
0
                                            &current->name.directoryName,
1478
0
                                            SEC_OID_PKCS9_EMAIL_ADDRESS);
1479
0
                    pBuf =
1480
0
                        appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
1481
1482
0
                    rawEmailAddr =
1483
0
                        CERT_GetNameElement(&tmpArena.arena,
1484
0
                                            &current->name.directoryName,
1485
0
                                            SEC_OID_RFC1274_MAIL);
1486
0
                    pBuf =
1487
0
                        appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
1488
0
                } else if (current->type == certRFC822Name) {
1489
0
                    pBuf =
1490
0
                        appendItemToBuf(pBuf, &current->name.other, &maxLen);
1491
0
                }
1492
0
                current = CERT_GetNextGeneralName(current);
1493
0
            } while (current != nameList);
1494
0
        }
1495
0
        SECITEM_FreeItem(&subAltName, PR_FALSE);
1496
        /* Don't free nameList, it's part of the tmpArena. */
1497
0
    }
1498
    /* now copy superstring to cert's arena */
1499
0
    finalLen = (pBuf - addrBuf) + 1;
1500
0
    pBuf = NULL;
1501
0
    if (finalLen > 1) {
1502
0
        pBuf = PORT_ArenaAlloc(cert->arena, finalLen);
1503
0
        if (pBuf) {
1504
0
            PORT_Memcpy(pBuf, addrBuf, finalLen);
1505
0
        }
1506
0
    }
1507
0
loser:
1508
0
    PORT_DestroyCheapArena(&tmpArena);
1509
1510
0
    return pBuf;
1511
0
}
1512
1513
/* returns pointer to storage in cert's arena.  Storage remains valid
1514
** as long as cert's reference count doesn't go to zero.
1515
** Caller should strdup or otherwise copy.
1516
*/
1517
const char* /* const so caller won't muck with it. */
1518
CERT_GetFirstEmailAddress(CERTCertificate* cert)
1519
0
{
1520
0
    if (cert && cert->emailAddr && cert->emailAddr[0])
1521
0
        return (const char*)cert->emailAddr;
1522
0
    return NULL;
1523
0
}
1524
1525
/* returns pointer to storage in cert's arena.  Storage remains valid
1526
** as long as cert's reference count doesn't go to zero.
1527
** Caller should strdup or otherwise copy.
1528
*/
1529
const char* /* const so caller won't muck with it. */
1530
CERT_GetNextEmailAddress(CERTCertificate* cert, const char* prev)
1531
0
{
1532
0
    if (cert && prev && prev[0]) {
1533
0
        PRUint32 len = PL_strlen(prev);
1534
0
        prev += len + 1;
1535
0
        if (prev && prev[0])
1536
0
            return prev;
1537
0
    }
1538
0
    return NULL;
1539
0
}
1540
1541
/* This is seriously bogus, now that certs store their email addresses in
1542
** subject Alternative Name extensions.
1543
** Returns a string allocated by PORT_StrDup, which the caller must free.
1544
*/
1545
char*
1546
CERT_GetCertEmailAddress(const CERTName* name)
1547
0
{
1548
0
    char* rawEmailAddr;
1549
0
    char* emailAddr;
1550
1551
0
    rawEmailAddr = CERT_GetNameElement(NULL, name, SEC_OID_PKCS9_EMAIL_ADDRESS);
1552
0
    if (rawEmailAddr == NULL) {
1553
0
        rawEmailAddr = CERT_GetNameElement(NULL, name, SEC_OID_RFC1274_MAIL);
1554
0
    }
1555
0
    emailAddr = CERT_FixupEmailAddr(rawEmailAddr);
1556
0
    if (rawEmailAddr) {
1557
0
        PORT_Free(rawEmailAddr);
1558
0
    }
1559
0
    return (emailAddr);
1560
0
}
1561
1562
/* The return value must be freed with PORT_Free. */
1563
char*
1564
CERT_GetCommonName(const CERTName* name)
1565
0
{
1566
0
    return (CERT_GetLastNameElement(NULL, name, SEC_OID_AVA_COMMON_NAME));
1567
0
}
1568
1569
char*
1570
CERT_GetCountryName(const CERTName* name)
1571
0
{
1572
0
    return (CERT_GetNameElement(NULL, name, SEC_OID_AVA_COUNTRY_NAME));
1573
0
}
1574
1575
char*
1576
CERT_GetLocalityName(const CERTName* name)
1577
0
{
1578
0
    return (CERT_GetNameElement(NULL, name, SEC_OID_AVA_LOCALITY));
1579
0
}
1580
1581
char*
1582
CERT_GetStateName(const CERTName* name)
1583
0
{
1584
0
    return (CERT_GetNameElement(NULL, name, SEC_OID_AVA_STATE_OR_PROVINCE));
1585
0
}
1586
1587
char*
1588
CERT_GetOrgName(const CERTName* name)
1589
0
{
1590
0
    return (CERT_GetNameElement(NULL, name, SEC_OID_AVA_ORGANIZATION_NAME));
1591
0
}
1592
1593
char*
1594
CERT_GetDomainComponentName(const CERTName* name)
1595
0
{
1596
0
    return (CERT_GetNameElement(NULL, name, SEC_OID_AVA_DC));
1597
0
}
1598
1599
char*
1600
CERT_GetOrgUnitName(const CERTName* name)
1601
0
{
1602
0
    return (
1603
0
        CERT_GetNameElement(NULL, name, SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME));
1604
0
}
1605
1606
char*
1607
CERT_GetDnQualifier(const CERTName* name)
1608
0
{
1609
0
    return (CERT_GetNameElement(NULL, name, SEC_OID_AVA_DN_QUALIFIER));
1610
0
}
1611
1612
char*
1613
CERT_GetCertUid(const CERTName* name)
1614
0
{
1615
0
    return (CERT_GetNameElement(NULL, name, SEC_OID_RFC1274_UID));
1616
0
}