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