Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(176)

Side by Side Diff: nss/lib/certdb/alg1485.c

Issue 2078763002: Delete bundled copy of NSS and replace with README. (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/nss@master
Patch Set: Delete bundled copy of NSS and replace with README. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « nss/lib/base/tracker.c ('k') | nss/lib/certdb/cert.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
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
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
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
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
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
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 dest = destItem->data;
347 for (; len > 0; len--, src += 2) {
348 PRInt16 bin = (x2b[(PRUint8)src[0]] << 4) | x2b[(PRUint8)src[1]];
349 if (bin < 0)
350 goto loser;
351 *dest++ = (PRUint8)bin;
352 }
353 return SECSuccess;
354 loser:
355 if (!pool)
356 SECITEM_FreeItem(destItem, PR_FALSE);
357 return SECFailure;
358 }
359
360 /* Parses one AVA, starting at *pbp. Stops at endptr.
361 * Advances *pbp past parsed AVA and trailing separator (if present).
362 * On any error, returns NULL and *pbp is undefined.
363 * On success, returns CERTAVA allocated from arena, and (*pbp)[-1] was
364 * the last character parsed. *pbp is either equal to endptr or
365 * points to first character after separator.
366 */
367 static CERTAVA*
368 ParseRFC1485AVA(PLArenaPool* arena, const char** pbp, const char* endptr)
369 {
370 CERTAVA* a;
371 const NameToKind* n2k;
372 const char* bp;
373 int vt = -1;
374 int valLen;
375 SECOidTag kind = SEC_OID_UNKNOWN;
376 SECStatus rv = SECFailure;
377 SECItem derOid = { 0, NULL, 0 };
378 SECItem derVal = { 0, NULL, 0 };
379 char sep = 0;
380
381 char tagBuf[32];
382 char valBuf[1024];
383
384 PORT_Assert(arena);
385 if (SECSuccess != scanTag(pbp, endptr, tagBuf, sizeof tagBuf) ||
386 !(valLen = scanVal(pbp, endptr, valBuf, sizeof valBuf))) {
387 goto loser;
388 }
389
390 bp = *pbp;
391 if (bp < endptr) {
392 sep = *bp++; /* skip over separator */
393 }
394 *pbp = bp;
395 /* if we haven't finished, insist that we've stopped on a separator */
396 if (sep && sep != ',' && sep != ';' && sep != '+') {
397 goto loser;
398 }
399
400 /* is this a dotted decimal OID attribute type ? */
401 if (!PL_strncasecmp("oid.", tagBuf, 4)) {
402 rv = SEC_StringToOID(arena, &derOid, tagBuf, strlen(tagBuf));
403 } else {
404 for (n2k = name2kinds; n2k->name; n2k++) {
405 SECOidData* oidrec;
406 if (PORT_Strcasecmp(n2k->name, tagBuf) == 0) {
407 kind = n2k->kind;
408 vt = n2k->valueType;
409 oidrec = SECOID_FindOIDByTag(kind);
410 if (oidrec == NULL)
411 goto loser;
412 derOid = oidrec->oid;
413 break;
414 }
415 }
416 }
417 if (kind == SEC_OID_UNKNOWN && rv != SECSuccess)
418 goto loser;
419
420 /* Is this a hex encoding of a DER attribute value ? */
421 if ('#' == valBuf[0]) {
422 /* convert attribute value from hex to binary */
423 rv = hexToBin(arena, &derVal, valBuf + 1, valLen - 1);
424 if (rv)
425 goto loser;
426 a = CERT_CreateAVAFromRaw(arena, &derOid, &derVal);
427 } else {
428 if (kind == SEC_OID_UNKNOWN)
429 goto loser;
430 if (kind == SEC_OID_AVA_COUNTRY_NAME && valLen != 2)
431 goto loser;
432 if (vt == SEC_ASN1_PRINTABLE_STRING &&
433 !IsPrintable((unsigned char*)valBuf, valLen))
434 goto loser;
435 if (vt == SEC_ASN1_DS) {
436 /* RFC 4630: choose PrintableString or UTF8String */
437 if (IsPrintable((unsigned char*)valBuf, valLen))
438 vt = SEC_ASN1_PRINTABLE_STRING;
439 else
440 vt = SEC_ASN1_UTF8_STRING;
441 }
442
443 derVal.data = (unsigned char*)valBuf;
444 derVal.len = valLen;
445 a = CERT_CreateAVAFromSECItem(arena, kind, vt, &derVal);
446 }
447 return a;
448
449 loser:
450 /* matched no kind -- invalid tag */
451 PORT_SetError(SEC_ERROR_INVALID_AVA);
452 return 0;
453 }
454
455 static CERTName*
456 ParseRFC1485Name(const char* buf, int len)
457 {
458 SECStatus rv;
459 CERTName* name;
460 const char *bp, *e;
461 CERTAVA* ava;
462 CERTRDN* rdn = NULL;
463
464 name = CERT_CreateName(NULL);
465 if (name == NULL) {
466 return NULL;
467 }
468
469 e = buf + len;
470 bp = buf;
471 while (bp < e) {
472 ava = ParseRFC1485AVA(name->arena, &bp, e);
473 if (ava == 0)
474 goto loser;
475 if (!rdn) {
476 rdn = CERT_CreateRDN(name->arena, ava, (CERTAVA*)0);
477 if (rdn == 0)
478 goto loser;
479 rv = CERT_AddRDN(name, rdn);
480 } else {
481 rv = CERT_AddAVA(name->arena, rdn, ava);
482 }
483 if (rv)
484 goto loser;
485 if (bp[-1] != '+')
486 rdn = NULL; /* done with this RDN */
487 skipSpace(&bp, e);
488 }
489
490 if (name->rdns[0] == 0) {
491 /* empty name -- illegal */
492 goto loser;
493 }
494
495 /* Reverse order of RDNS to comply with RFC */
496 {
497 CERTRDN** firstRdn;
498 CERTRDN** lastRdn;
499 CERTRDN* tmp;
500
501 /* get first one */
502 firstRdn = name->rdns;
503
504 /* find last one */
505 lastRdn = name->rdns;
506 while (*lastRdn)
507 lastRdn++;
508 lastRdn--;
509
510 /* reverse list */
511 for (; firstRdn < lastRdn; firstRdn++, lastRdn--) {
512 tmp = *firstRdn;
513 *firstRdn = *lastRdn;
514 *lastRdn = tmp;
515 }
516 }
517
518 /* return result */
519 return name;
520
521 loser:
522 CERT_DestroyName(name);
523 return NULL;
524 }
525
526 CERTName*
527 CERT_AsciiToName(const char* string)
528 {
529 CERTName* name;
530 name = ParseRFC1485Name(string, PORT_Strlen(string));
531 return name;
532 }
533
534 /************************************************************************/
535
536 typedef struct stringBufStr {
537 char* buffer;
538 unsigned offset;
539 unsigned size;
540 } stringBuf;
541
542 #define DEFAULT_BUFFER_SIZE 200
543
544 static SECStatus
545 AppendStr(stringBuf* bufp, char* str)
546 {
547 char* buf;
548 unsigned bufLen, bufSize, len;
549 int size = 0;
550
551 /* Figure out how much to grow buf by (add in the '\0') */
552 buf = bufp->buffer;
553 bufLen = bufp->offset;
554 len = PORT_Strlen(str);
555 bufSize = bufLen + len;
556 if (!buf) {
557 bufSize++;
558 size = PR_MAX(DEFAULT_BUFFER_SIZE, bufSize * 2);
559 buf = (char*)PORT_Alloc(size);
560 bufp->size = size;
561 } else if (bufp->size < bufSize) {
562 size = bufSize * 2;
563 buf = (char*)PORT_Realloc(buf, size);
564 bufp->size = size;
565 }
566 if (!buf) {
567 PORT_SetError(SEC_ERROR_NO_MEMORY);
568 return SECFailure;
569 }
570 bufp->buffer = buf;
571 bufp->offset = bufSize;
572
573 /* Concatenate str onto buf */
574 buf = buf + bufLen;
575 if (bufLen)
576 buf--; /* stomp on old '\0' */
577 PORT_Memcpy(buf, str, len + 1); /* put in new null */
578 return SECSuccess;
579 }
580
581 typedef enum {
582 minimalEscape = 0, /* only hex escapes, and " and \ */
583 minimalEscapeAndQuote, /* as above, plus quoting */
584 fullEscape /* no quoting, full escaping */
585 } EQMode;
586
587 /* Some characters must be escaped as a hex string, e.g. c -> \nn .
588 * Others must be escaped by preceding with a '\', e.g. c -> \c , but
589 * there are certain "special characters" that may be handled by either
590 * escaping them, or by enclosing the entire attribute value in quotes.
591 * A NULL value for pEQMode implies selecting minimalEscape mode.
592 * Some callers will do quoting when needed, others will not.
593 * If a caller selects minimalEscapeAndQuote, and the string does not
594 * need quoting, then this function changes it to minimalEscape.
595 */
596 static int
597 cert_RFC1485_GetRequiredLen(const char* src, int srclen, EQMode* pEQMode)
598 {
599 int i, reqLen = 0;
600 EQMode mode = pEQMode ? *pEQMode : minimalEscape;
601 PRBool needsQuoting = PR_FALSE;
602 char lastC = 0;
603
604 /* need to make an initial pass to determine if quoting is needed */
605 for (i = 0; i < srclen; i++) {
606 char c = src[i];
607 reqLen++;
608 if (NEEDS_HEX_ESCAPE(c)) { /* c -> \xx */
609 reqLen += 2;
610 } else if (NEEDS_ESCAPE(c)) { /* c -> \c */
611 reqLen++;
612 } else if (SPECIAL_CHAR(c)) {
613 if (mode == minimalEscapeAndQuote) /* quoting is allowed */
614 needsQuoting = PR_TRUE; /* entirety will need quoting */
615 else if (mode == fullEscape)
616 reqLen++; /* MAY escape this character */
617 } else if (OPTIONAL_SPACE(c) && OPTIONAL_SPACE(lastC)) {
618 if (mode == minimalEscapeAndQuote) /* quoting is allowed */
619 needsQuoting = PR_TRUE; /* entirety will need quoting */
620 }
621 lastC = c;
622 }
623 /* if it begins or ends in optional space it needs quoting */
624 if (!needsQuoting && srclen > 0 && mode == minimalEscapeAndQuote &&
625 (OPTIONAL_SPACE(src[srclen - 1]) || OPTIONAL_SPACE(src[0]))) {
626 needsQuoting = PR_TRUE;
627 }
628
629 if (needsQuoting)
630 reqLen += 2;
631 if (pEQMode && mode == minimalEscapeAndQuote && !needsQuoting)
632 *pEQMode = minimalEscape;
633 return reqLen;
634 }
635
636 static const char hexChars[16] = { "0123456789abcdef" };
637
638 static SECStatus
639 escapeAndQuote(char* dst, int dstlen, char* src, int srclen, EQMode* pEQMode)
640 {
641 int i, reqLen = 0;
642 EQMode mode = pEQMode ? *pEQMode : minimalEscape;
643
644 /* space for terminal null */
645 reqLen = cert_RFC1485_GetRequiredLen(src, srclen, &mode) + 1;
646 if (reqLen > dstlen) {
647 PORT_SetError(SEC_ERROR_OUTPUT_LEN);
648 return SECFailure;
649 }
650
651 if (mode == minimalEscapeAndQuote)
652 *dst++ = C_DOUBLE_QUOTE;
653 for (i = 0; i < srclen; i++) {
654 char c = src[i];
655 if (NEEDS_HEX_ESCAPE(c)) {
656 *dst++ = C_BACKSLASH;
657 *dst++ = hexChars[(c >> 4) & 0x0f];
658 *dst++ = hexChars[c & 0x0f];
659 } else {
660 if (NEEDS_ESCAPE(c) || (SPECIAL_CHAR(c) && mode == fullEscape)) {
661 *dst++ = C_BACKSLASH;
662 }
663 *dst++ = c;
664 }
665 }
666 if (mode == minimalEscapeAndQuote)
667 *dst++ = C_DOUBLE_QUOTE;
668 *dst++ = 0;
669 if (pEQMode)
670 *pEQMode = mode;
671 return SECSuccess;
672 }
673
674 SECStatus
675 CERT_RFC1485_EscapeAndQuote(char* dst, int dstlen, char* src, int srclen)
676 {
677 EQMode mode = minimalEscapeAndQuote;
678 return escapeAndQuote(dst, dstlen, src, srclen, &mode);
679 }
680
681 /* convert an OID to dotted-decimal representation */
682 /* Returns a string that must be freed with PR_smprintf_free(), */
683 char*
684 CERT_GetOidString(const SECItem* oid)
685 {
686 PRUint8* stop; /* points to first byte after OID string */
687 PRUint8* first; /* byte of an OID component integer */
688 PRUint8* last; /* byte of an OID component integer */
689 char* rvString = NULL;
690 char* prefix = NULL;
691
692 #define MAX_OID_LEN 1024 /* bytes */
693
694 if (oid->len > MAX_OID_LEN) {
695 PORT_SetError(SEC_ERROR_INPUT_LEN);
696 return NULL;
697 }
698
699 /* first will point to the next sequence of bytes to decode */
700 first = (PRUint8*)oid->data;
701 /* stop points to one past the legitimate data */
702 stop = &first[oid->len];
703
704 /*
705 * Check for our pseudo-encoded single-digit OIDs
706 */
707 if ((*first == 0x80) && (2 == oid->len)) {
708 /* Funky encoding. The second byte is the number */
709 rvString = PR_smprintf("%lu", (PRUint32)first[1]);
710 if (!rvString) {
711 PORT_SetError(SEC_ERROR_NO_MEMORY);
712 }
713 return rvString;
714 }
715
716 for (; first < stop; first = last + 1) {
717 unsigned int bytesBeforeLast;
718
719 for (last = first; last < stop; last++) {
720 if (0 == (*last & 0x80)) {
721 break;
722 }
723 }
724 bytesBeforeLast = (unsigned int)(last - first);
725 if (bytesBeforeLast <= 3U) { /* 0-28 bit number */
726 PRUint32 n = 0;
727 PRUint32 c;
728
729 #define CGET(i, m) \
730 c = last[-i] & m; \
731 n |= c << (7 * i)
732
733 #define CASE(i, m) \
734 case i: \
735 CGET(i, m); \
736 if (!n) \
737 goto unsupported /* fall-through */
738
739 switch (bytesBeforeLast) {
740 CASE(3, 0x7f);
741 CASE(2, 0x7f);
742 CASE(1, 0x7f);
743 case 0:
744 n |=
745 last[0] & 0x7f;
746 break;
747 }
748 if (last[0] & 0x80)
749 goto unsupported;
750
751 if (!rvString) {
752 /* This is the first number.. decompose it */
753 PRUint32 one = PR_MIN(n / 40, 2); /* never > 2 */
754 PRUint32 two = n - (one * 40);
755
756 rvString = PR_smprintf("OID.%lu.%lu", one, two);
757 } else {
758 prefix = rvString;
759 rvString = PR_smprintf("%s.%lu", prefix, n);
760 }
761 } else if (bytesBeforeLast <= 9U) { /* 29-64 bit number */
762 PRUint64 n = 0;
763 PRUint64 c;
764
765 switch (bytesBeforeLast) {
766 CASE(9, 0x01);
767 CASE(8, 0x7f);
768 CASE(7, 0x7f);
769 CASE(6, 0x7f);
770 CASE(5, 0x7f);
771 CASE(4, 0x7f);
772 CGET(3, 0x7f);
773 CGET(2, 0x7f);
774 CGET(1, 0x7f);
775 CGET(0, 0x7f);
776 break;
777 }
778 if (last[0] & 0x80)
779 goto unsupported;
780
781 if (!rvString) {
782 /* This is the first number.. decompose it */
783 PRUint64 one = PR_MIN(n / 40, 2); /* never > 2 */
784 PRUint64 two = n - (one * 40);
785
786 rvString = PR_smprintf("OID.%llu.%llu", one, two);
787 } else {
788 prefix = rvString;
789 rvString = PR_smprintf("%s.%llu", prefix, n);
790 }
791 } else {
792 /* More than a 64-bit number, or not minimal encoding. */
793 unsupported:
794 if (!rvString)
795 rvString = PR_smprintf("OID.UNSUPPORTED");
796 else {
797 prefix = rvString;
798 rvString = PR_smprintf("%s.UNSUPPORTED", prefix);
799 }
800 }
801
802 if (prefix) {
803 PR_smprintf_free(prefix);
804 prefix = NULL;
805 }
806 if (!rvString) {
807 PORT_SetError(SEC_ERROR_NO_MEMORY);
808 break;
809 }
810 }
811 return rvString;
812 }
813
814 /* convert DER-encoded hex to a string */
815 static SECItem*
816 get_hex_string(SECItem* data)
817 {
818 SECItem* rv;
819 unsigned int i, j;
820 static const char hex[] = { "0123456789ABCDEF" };
821
822 /* '#' + 2 chars per octet + terminator */
823 rv = SECITEM_AllocItem(NULL, NULL, data->len * 2 + 2);
824 if (!rv) {
825 return NULL;
826 }
827 rv->data[0] = '#';
828 rv->len = 1 + 2 * data->len;
829 for (i = 0; i < data->len; i++) {
830 j = data->data[i];
831 rv->data[2 * i + 1] = hex[j >> 4];
832 rv->data[2 * i + 2] = hex[j & 15];
833 }
834 rv->data[rv->len] = 0;
835 return rv;
836 }
837
838 /* For compliance with RFC 2253, RFC 3280 and RFC 4630, we choose to
839 * use the NAME=STRING form, rather than the OID.N.N=#hexXXXX form,
840 * when both of these conditions are met:
841 * 1) The attribute name OID (kind) has a known name string that is
842 * defined in one of those RFCs, or in RFCs that they cite, AND
843 * 2) The attribute's value encoding is RFC compliant for the kind
844 * (e.g., the value's encoding tag is correct for the kind, and
845 * the value's length is in the range allowed for the kind, and
846 * the value's contents are appropriate for the encoding tag).
847 * Otherwise, we use the OID.N.N=#hexXXXX form.
848 *
849 * If the caller prefers maximum human readability to RFC compliance,
850 * then
851 * - We print the kind in NAME= string form if we know the name
852 * string for the attribute type OID, regardless of whether the
853 * value is correctly encoded or not. else we use the OID.N.N= form.
854 * - We use the non-hex STRING form for the attribute value if the
855 * value can be represented in such a form. Otherwise, we use
856 * the hex string form.
857 * This implies that, for maximum human readability, in addition to
858 * the two forms allowed by the RFC, we allow two other forms of output:
859 * - the OID.N.N=STRING form, and
860 * - the NAME=#hexXXXX form
861 * When the caller prefers maximum human readability, we do not allow
862 * the value of any attribute to exceed the length allowed by the RFC.
863 * If the attribute value exceeds the allowed length, we truncate it to
864 * the allowed length and append "...".
865 * Also in this case, we arbitrarily impose a limit on the length of the
866 * entire AVA encoding, regardless of the form, of 384 bytes per AVA.
867 * This limit includes the trailing NULL character. If the encoded
868 * AVA length exceeds that limit, this function reports failure to encode
869 * the AVA.
870 *
871 * An ASCII representation of an AVA is said to be "invertible" if
872 * conversion back to DER reproduces the original DER encoding exactly.
873 * The RFC 2253 rules do not ensure that all ASCII AVAs derived according
874 * to its rules are invertible. That is because the RFCs allow some
875 * attribute values to be encoded in any of a number of encodings,
876 * and the encoding type information is lost in the non-hex STRING form.
877 * This is particularly true of attributes of type DirectoryString.
878 * The encoding type information is always preserved in the hex string
879 * form, because the hex includes the entire DER encoding of the value.
880 *
881 * So, when the caller perfers maximum invertibility, we apply the
882 * RFC compliance rules stated above, and add a third required
883 * condition on the use of the NAME=STRING form.
884 * 3) The attribute's kind is not is allowed to be encoded in any of
885 * several different encodings, such as DirectoryStrings.
886 *
887 * The chief difference between CERT_N2A_STRICT and CERT_N2A_INVERTIBLE
888 * is that the latter forces DirectoryStrings to be hex encoded.
889 *
890 * As a simplification, we assume the value is correctly encoded for
891 * its encoding type. That is, we do not test that all the characters
892 * in a string encoded type are allowed by that type. We assume it.
893 */
894 static SECStatus
895 AppendAVA(stringBuf* bufp, CERTAVA* ava, CertStrictnessLevel strict)
896 {
897 #define TMPBUF_LEN 2048
898 const NameToKind* pn2k = name2kinds;
899 SECItem* avaValue = NULL;
900 char* unknownTag = NULL;
901 char* encodedAVA = NULL;
902 PRBool useHex = PR_FALSE; /* use =#hexXXXX form */
903 PRBool truncateName = PR_FALSE;
904 PRBool truncateValue = PR_FALSE;
905 SECOidTag endKind;
906 SECStatus rv;
907 unsigned int len;
908 unsigned int nameLen, valueLen;
909 unsigned int maxName, maxValue;
910 EQMode mode = minimalEscapeAndQuote;
911 NameToKind n2k = { NULL, 32767, SEC_OID_UNKNOWN, SEC_ASN1_DS };
912 char tmpBuf[TMPBUF_LEN];
913
914 #define tagName n2k.name /* non-NULL means use NAME= form */
915 #define maxBytes n2k.maxLen
916 #define tag n2k.kind
917 #define vt n2k.valueType
918
919 /* READABLE mode recognizes more names from the name2kinds table
920 * than do STRICT or INVERTIBLE modes. This assignment chooses the
921 * point in the table where the attribute type name scanning stops.
922 */
923 endKind = (strict == CERT_N2A_READABLE) ? SEC_OID_UNKNOWN
924 : SEC_OID_AVA_POSTAL_ADDRESS;
925 tag = CERT_GetAVATag(ava);
926 while (pn2k->kind != tag && pn2k->kind != endKind) {
927 ++pn2k;
928 }
929
930 if (pn2k->kind != endKind) {
931 n2k = *pn2k;
932 } else if (strict != CERT_N2A_READABLE) {
933 useHex = PR_TRUE;
934 }
935 /* For invertable form, force Directory Strings to use hex form. */
936 if (strict == CERT_N2A_INVERTIBLE && vt == SEC_ASN1_DS) {
937 tagName = NULL; /* must use OID.N form */
938 useHex = PR_TRUE; /* must use hex string */
939 }
940 if (!useHex) {
941 avaValue = CERT_DecodeAVAValue(&ava->value);
942 if (!avaValue) {
943 useHex = PR_TRUE;
944 if (strict != CERT_N2A_READABLE) {
945 tagName = NULL; /* must use OID.N form */
946 }
947 }
948 }
949 if (!tagName) {
950 /* handle unknown attribute types per RFC 2253 */
951 tagName = unknownTag = CERT_GetOidString(&ava->type);
952 if (!tagName) {
953 if (avaValue)
954 SECITEM_FreeItem(avaValue, PR_TRUE);
955 return SECFailure;
956 }
957 }
958 if (useHex) {
959 avaValue = get_hex_string(&ava->value);
960 if (!avaValue) {
961 if (unknownTag)
962 PR_smprintf_free(unknownTag);
963 return SECFailure;
964 }
965 }
966
967 nameLen = strlen(tagName);
968 valueLen =
969 (useHex ? avaValue->len : cert_RFC1485_GetRequiredLen(
970 (char*)avaValue->data, avaValue->len, &mod e));
971 len = nameLen + valueLen + 2; /* Add 2 for '=' and trailing NUL */
972
973 maxName = nameLen;
974 maxValue = valueLen;
975 if (len <= sizeof(tmpBuf)) {
976 encodedAVA = tmpBuf;
977 } else if (strict != CERT_N2A_READABLE) {
978 encodedAVA = PORT_Alloc(len);
979 if (!encodedAVA) {
980 SECITEM_FreeItem(avaValue, PR_TRUE);
981 if (unknownTag)
982 PR_smprintf_free(unknownTag);
983 return SECFailure;
984 }
985 } else {
986 /* Must make output fit in tmpbuf */
987 unsigned int fair = (sizeof tmpBuf) / 2 - 1; /* for = and \0 */
988
989 if (nameLen < fair) {
990 /* just truncate the value */
991 maxValue = (sizeof tmpBuf) - (nameLen + 6); /* for "=...\0",
992 and possibly '"' */
993 } else if (valueLen < fair) {
994 /* just truncate the name */
995 maxName = (sizeof tmpBuf) - (valueLen + 5); /* for "=...\0" */
996 } else {
997 /* truncate both */
998 maxName = maxValue = fair - 3; /* for "..." */
999 }
1000 if (nameLen > maxName) {
1001 PORT_Assert(unknownTag && unknownTag == tagName);
1002 truncateName = PR_TRUE;
1003 nameLen = maxName;
1004 }
1005 encodedAVA = tmpBuf;
1006 }
1007
1008 memcpy(encodedAVA, tagName, nameLen);
1009 if (truncateName) {
1010 /* If tag name is too long, we know it is an OID form that was
1011 * allocated from the heap, so we can modify it in place
1012 */
1013 encodedAVA[nameLen - 1] = '.';
1014 encodedAVA[nameLen - 2] = '.';
1015 encodedAVA[nameLen - 3] = '.';
1016 }
1017 encodedAVA[nameLen++] = '=';
1018 if (unknownTag)
1019 PR_smprintf_free(unknownTag);
1020
1021 if (strict == CERT_N2A_READABLE && maxValue > maxBytes)
1022 maxValue = maxBytes;
1023 if (valueLen > maxValue) {
1024 valueLen = maxValue;
1025 truncateValue = PR_TRUE;
1026 }
1027 /* escape and quote as necessary - don't quote hex strings */
1028 if (useHex) {
1029 char* end = encodedAVA + nameLen + valueLen;
1030 memcpy(encodedAVA + nameLen, (char*)avaValue->data, valueLen);
1031 end[0] = '\0';
1032 if (truncateValue) {
1033 end[-1] = '.';
1034 end[-2] = '.';
1035 end[-3] = '.';
1036 }
1037 rv = SECSuccess;
1038 } else if (!truncateValue) {
1039 rv = escapeAndQuote(encodedAVA + nameLen, len - nameLen,
1040 (char*)avaValue->data, avaValue->len, &mode);
1041 } else {
1042 /* must truncate the escaped and quoted value */
1043 char bigTmpBuf[TMPBUF_LEN * 3 + 3];
1044 PORT_Assert(valueLen < sizeof tmpBuf);
1045 rv = escapeAndQuote(bigTmpBuf, sizeof bigTmpBuf, (char*)avaValue->data,
1046 PR_MIN(avaValue->len, valueLen), &mode);
1047
1048 bigTmpBuf[valueLen--] = '\0'; /* hard stop here */
1049 /* See if we're in the middle of a multi-byte UTF8 character */
1050 while (((bigTmpBuf[valueLen] & 0xc0) == 0x80) && valueLen > 0) {
1051 bigTmpBuf[valueLen--] = '\0';
1052 }
1053 /* add ellipsis to signify truncation. */
1054 bigTmpBuf[++valueLen] = '.';
1055 bigTmpBuf[++valueLen] = '.';
1056 bigTmpBuf[++valueLen] = '.';
1057 if (bigTmpBuf[0] == '"')
1058 bigTmpBuf[++valueLen] = '"';
1059 bigTmpBuf[++valueLen] = '\0';
1060 PORT_Assert(nameLen + valueLen <= (sizeof tmpBuf) - 1);
1061 memcpy(encodedAVA + nameLen, bigTmpBuf, valueLen + 1);
1062 }
1063
1064 SECITEM_FreeItem(avaValue, PR_TRUE);
1065 if (rv == SECSuccess)
1066 rv = AppendStr(bufp, encodedAVA);
1067 if (encodedAVA != tmpBuf)
1068 PORT_Free(encodedAVA);
1069 return rv;
1070 }
1071
1072 #undef tagName
1073 #undef maxBytes
1074 #undef tag
1075 #undef vt
1076
1077 char*
1078 CERT_NameToAsciiInvertible(CERTName* name, CertStrictnessLevel strict)
1079 {
1080 CERTRDN** rdns;
1081 CERTRDN** lastRdn;
1082 CERTRDN** rdn;
1083 PRBool first = PR_TRUE;
1084 stringBuf strBuf = { NULL, 0, 0 };
1085
1086 rdns = name->rdns;
1087 if (rdns == NULL) {
1088 return NULL;
1089 }
1090
1091 /* find last RDN */
1092 lastRdn = rdns;
1093 while (*lastRdn)
1094 lastRdn++;
1095 lastRdn--;
1096
1097 /*
1098 * Loop over name contents in _reverse_ RDN order appending to string
1099 */
1100 for (rdn = lastRdn; rdn >= rdns; rdn--) {
1101 CERTAVA** avas = (*rdn)->avas;
1102 CERTAVA* ava;
1103 PRBool newRDN = PR_TRUE;
1104
1105 /*
1106 * XXX Do we need to traverse the AVAs in reverse order, too?
1107 */
1108 while (avas && (ava = *avas++) != NULL) {
1109 SECStatus rv;
1110 /* Put in comma or plus separator */
1111 if (!first) {
1112 /* Use of spaces is deprecated in RFC 2253. */
1113 rv = AppendStr(&strBuf, newRDN ? "," : "+");
1114 if (rv)
1115 goto loser;
1116 } else {
1117 first = PR_FALSE;
1118 }
1119
1120 /* Add in tag type plus value into strBuf */
1121 rv = AppendAVA(&strBuf, ava, strict);
1122 if (rv)
1123 goto loser;
1124 newRDN = PR_FALSE;
1125 }
1126 }
1127 return strBuf.buffer;
1128 loser:
1129 if (strBuf.buffer) {
1130 PORT_Free(strBuf.buffer);
1131 }
1132 return NULL;
1133 }
1134
1135 char*
1136 CERT_NameToAscii(CERTName* name)
1137 {
1138 return CERT_NameToAsciiInvertible(name, CERT_N2A_READABLE);
1139 }
1140
1141 /*
1142 * Return the string representation of a DER encoded distinguished name
1143 * "dername" - The DER encoded name to convert
1144 */
1145 char*
1146 CERT_DerNameToAscii(SECItem* dername)
1147 {
1148 int rv;
1149 PLArenaPool* arena = NULL;
1150 CERTName name;
1151 char* retstr = NULL;
1152
1153 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1154
1155 if (arena == NULL) {
1156 goto loser;
1157 }
1158
1159 rv = SEC_QuickDERDecodeItem(arena, &name, CERT_NameTemplate, dername);
1160
1161 if (rv != SECSuccess) {
1162 goto loser;
1163 }
1164
1165 retstr = CERT_NameToAscii(&name);
1166
1167 loser:
1168 if (arena != NULL) {
1169 PORT_FreeArena(arena, PR_FALSE);
1170 }
1171
1172 return (retstr);
1173 }
1174
1175 static char*
1176 avaToString(PLArenaPool* arena, CERTAVA* ava)
1177 {
1178 char* buf = NULL;
1179 SECItem* avaValue;
1180 int valueLen;
1181
1182 avaValue = CERT_DecodeAVAValue(&ava->value);
1183 if (!avaValue) {
1184 return buf;
1185 }
1186 valueLen =
1187 cert_RFC1485_GetRequiredLen((char*)avaValue->data, avaValue->len, NULL) + 1;
1188 if (arena) {
1189 buf = (char*)PORT_ArenaZAlloc(arena, valueLen);
1190 } else {
1191 buf = (char*)PORT_ZAlloc(valueLen);
1192 }
1193 if (buf) {
1194 SECStatus rv =
1195 escapeAndQuote(buf, valueLen, (char*)avaValue->data, avaValue->len, NULL);
1196 if (rv != SECSuccess) {
1197 if (!arena)
1198 PORT_Free(buf);
1199 buf = NULL;
1200 }
1201 }
1202 SECITEM_FreeItem(avaValue, PR_TRUE);
1203 return buf;
1204 }
1205
1206 /* RDNs are sorted from most general to most specific.
1207 * This code returns the FIRST one found, the most general one found.
1208 */
1209 static char*
1210 CERT_GetNameElement(PLArenaPool* arena, const CERTName* name, int wantedTag)
1211 {
1212 CERTRDN** rdns = name->rdns;
1213 CERTRDN* rdn;
1214 CERTAVA* ava = NULL;
1215
1216 while (rdns && (rdn = *rdns++) != 0) {
1217 CERTAVA** avas = rdn->avas;
1218 while (avas && (ava = *avas++) != 0) {
1219 int tag = CERT_GetAVATag(ava);
1220 if (tag == wantedTag) {
1221 avas = NULL;
1222 rdns = NULL; /* break out of all loops */
1223 }
1224 }
1225 }
1226 return ava ? avaToString(arena, ava) : NULL;
1227 }
1228
1229 /* RDNs are sorted from most general to most specific.
1230 * This code returns the LAST one found, the most specific one found.
1231 * This is particularly appropriate for Common Name. See RFC 2818.
1232 */
1233 static char*
1234 CERT_GetLastNameElement(PLArenaPool* arena, const CERTName* name, int wantedTag)
1235 {
1236 CERTRDN** rdns = name->rdns;
1237 CERTRDN* rdn;
1238 CERTAVA* lastAva = NULL;
1239
1240 while (rdns && (rdn = *rdns++) != 0) {
1241 CERTAVA** avas = rdn->avas;
1242 CERTAVA* ava;
1243 while (avas && (ava = *avas++) != 0) {
1244 int tag = CERT_GetAVATag(ava);
1245 if (tag == wantedTag) {
1246 lastAva = ava;
1247 }
1248 }
1249 }
1250 return lastAva ? avaToString(arena, lastAva) : NULL;
1251 }
1252
1253 char*
1254 CERT_GetCertificateEmailAddress(CERTCertificate* cert)
1255 {
1256 char* rawEmailAddr = NULL;
1257 SECItem subAltName;
1258 SECStatus rv;
1259 CERTGeneralName* nameList = NULL;
1260 CERTGeneralName* current;
1261 PLArenaPool* arena = NULL;
1262 int i;
1263
1264 subAltName.data = NULL;
1265
1266 rawEmailAddr = CERT_GetNameElement(cert->arena, &(cert->subject),
1267 SEC_OID_PKCS9_EMAIL_ADDRESS);
1268 if (rawEmailAddr == NULL) {
1269 rawEmailAddr =
1270 CERT_GetNameElement(cert->arena, &(cert->subject), SEC_OID_RFC1274_M AIL);
1271 }
1272 if (rawEmailAddr == NULL) {
1273
1274 rv =
1275 CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, &subAltN ame);
1276 if (rv != SECSuccess) {
1277 goto finish;
1278 }
1279 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1280 if (!arena) {
1281 goto finish;
1282 }
1283 nameList = current = CERT_DecodeAltNameExtension(arena, &subAltName);
1284 if (!nameList) {
1285 goto finish;
1286 }
1287 if (nameList != NULL) {
1288 do {
1289 if (current->type == certDirectoryName) {
1290 rawEmailAddr =
1291 CERT_GetNameElement(cert->arena, &(current->name.directo ryName),
1292 SEC_OID_PKCS9_EMAIL_ADDRESS);
1293 if (rawEmailAddr ==
1294 NULL) {
1295 rawEmailAddr =
1296 CERT_GetNameElement(cert->arena, &(current->name.dir ectoryName),
1297 SEC_OID_RFC1274_MAIL);
1298 }
1299 } else if (current->type == certRFC822Name) {
1300 rawEmailAddr =
1301 (char*)PORT_ArenaZAlloc(cert->arena, current->name.other .len +
1302 1);
1303 if (!rawEmailAddr) {
1304 goto finish;
1305 }
1306 PORT_Memcpy(rawEmailAddr, current->name.other.data,
1307 current->name.other.len);
1308 rawEmailAddr[current->name.other.len] =
1309 '\0';
1310 }
1311 if (rawEmailAddr) {
1312 break;
1313 }
1314 current = CERT_GetNextGeneralName(current);
1315 } while (current != nameList);
1316 }
1317 }
1318 if (rawEmailAddr) {
1319 for (i = 0; i <= (int)PORT_Strlen(rawEmailAddr); i++) {
1320 rawEmailAddr[i] = tolower(rawEmailAddr[i]);
1321 }
1322 }
1323
1324 finish:
1325
1326 /* Don't free nameList, it's part of the arena. */
1327
1328 if (arena) {
1329 PORT_FreeArena(arena, PR_FALSE);
1330 }
1331
1332 if (subAltName.data) {
1333 SECITEM_FreeItem(&subAltName, PR_FALSE);
1334 }
1335
1336 return (rawEmailAddr);
1337 }
1338
1339 static char*
1340 appendStringToBuf(char* dest, char* src, PRUint32* pRemaining)
1341 {
1342 PRUint32 len;
1343 if (dest && src && src[0] && *pRemaining > (len = PL_strlen(src))) {
1344 PRUint32 i;
1345 for (i = 0; i < len; ++i)
1346 dest[i] = tolower(src[i]);
1347 dest[len] = 0;
1348 dest += len + 1;
1349 *pRemaining -= len + 1;
1350 }
1351 return dest;
1352 }
1353
1354 #undef NEEDS_HEX_ESCAPE
1355 #define NEEDS_HEX_ESCAPE(c) (c < 0x20)
1356
1357 static char*
1358 appendItemToBuf(char* dest, SECItem* src, PRUint32* pRemaining)
1359 {
1360 if (dest && src && src->data && src->len && src->data[0]) {
1361 PRUint32 len = src->len;
1362 PRUint32 i;
1363 PRUint32 reqLen = len + 1;
1364 /* are there any embedded control characters ? */
1365 for (i = 0; i < len; i++) {
1366 if (NEEDS_HEX_ESCAPE(src->data[i]))
1367 reqLen += 2;
1368 }
1369 if (*pRemaining > reqLen) {
1370 for (i = 0; i < len; ++i) {
1371 PRUint8 c = src->data[i];
1372 if (NEEDS_HEX_ESCAPE(c)) {
1373 *dest++ =
1374 C_BACKSLASH;
1375 *dest++ =
1376 hexChars[(c >> 4) & 0x0f];
1377 *dest++ =
1378 hexChars[c & 0x0f];
1379 } else {
1380 *dest++ =
1381 tolower(c);
1382 }
1383 }
1384 *dest++ = '\0';
1385 *pRemaining -= reqLen;
1386 }
1387 }
1388 return dest;
1389 }
1390
1391 /* Returns a pointer to an environment-like string, a series of
1392 ** null-terminated strings, terminated by a zero-length string.
1393 ** This function is intended to be internal to NSS.
1394 */
1395 char*
1396 cert_GetCertificateEmailAddresses(CERTCertificate* cert)
1397 {
1398 char* rawEmailAddr = NULL;
1399 char* addrBuf = NULL;
1400 char* pBuf = NULL;
1401 PLArenaPool* tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1402 PRUint32 maxLen = 0;
1403 PRInt32 finalLen = 0;
1404 SECStatus rv;
1405 SECItem subAltName;
1406
1407 if (!tmpArena)
1408 return addrBuf;
1409
1410 subAltName.data = NULL;
1411 maxLen = cert->derCert.len;
1412 PORT_Assert(maxLen);
1413 if (!maxLen)
1414 maxLen = 2000; /* a guess, should never happen */
1415
1416 pBuf = addrBuf = (char*)PORT_ArenaZAlloc(tmpArena, maxLen + 1);
1417 if (!addrBuf)
1418 goto loser;
1419
1420 rawEmailAddr =
1421 CERT_GetNameElement(tmpArena, &cert->subject, SEC_OID_PKCS9_EMAIL_ADDRES S);
1422 pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
1423
1424 rawEmailAddr =
1425 CERT_GetNameElement(tmpArena, &cert->subject, SEC_OID_RFC1274_MAIL);
1426 pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
1427
1428 rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, &subAltName );
1429 if (rv == SECSuccess && subAltName.data) {
1430 CERTGeneralName* nameList = NULL;
1431
1432 if (!!(nameList = CERT_DecodeAltNameExtension(tmpArena, &subAltName))) {
1433 CERTGeneralName* current = nameList;
1434 do {
1435 if (current->type == certDirectoryName) {
1436 rawEmailAddr =
1437 CERT_GetNameElement(tmpArena, &current->name.directoryNa me,
1438 SEC_OID_PKCS9_EMAIL_ADDRESS);
1439 pBuf =
1440 appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
1441
1442 rawEmailAddr =
1443 CERT_GetNameElement(
1444 tmpArena, &current->name.directoryName, SEC_OID_RFC1 274_MAIL);
1445 pBuf =
1446 appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
1447 } else if (current->type == certRFC822Name) {
1448 pBuf =
1449 appendItemToBuf(pBuf, &current->name.other, &maxLen);
1450 }
1451 current = CERT_GetNextGeneralName(current);
1452 } while (current != nameList);
1453 }
1454 SECITEM_FreeItem(&subAltName, PR_FALSE);
1455 /* Don't free nameList, it's part of the tmpArena. */
1456 }
1457 /* now copy superstring to cert's arena */
1458 finalLen = (pBuf - addrBuf) + 1;
1459 pBuf = NULL;
1460 if (finalLen > 1) {
1461 pBuf = PORT_ArenaAlloc(cert->arena, finalLen);
1462 if (pBuf) {
1463 PORT_Memcpy(pBuf, addrBuf, finalLen);
1464 }
1465 }
1466 loser:
1467 if (tmpArena)
1468 PORT_FreeArena(tmpArena, PR_FALSE);
1469
1470 return pBuf;
1471 }
1472
1473 /* returns pointer to storage in cert's arena. Storage remains valid
1474 ** as long as cert's reference count doesn't go to zero.
1475 ** Caller should strdup or otherwise copy.
1476 */
1477 const char* /* const so caller won't muck with it. */
1478 CERT_GetFirstEmailAddress(CERTCertificate* cert)
1479 {
1480 if (cert && cert->emailAddr && cert->emailAddr[0])
1481 return (const char*)cert->emailAddr;
1482 return NULL;
1483 }
1484
1485 /* returns pointer to storage in cert's arena. Storage remains valid
1486 ** as long as cert's reference count doesn't go to zero.
1487 ** Caller should strdup or otherwise copy.
1488 */
1489 const char* /* const so caller won't muck with it. */
1490 CERT_GetNextEmailAddress(CERTCertificate* cert, const char* prev)
1491 {
1492 if (cert && prev && prev[0]) {
1493 PRUint32 len = PL_strlen(prev);
1494 prev += len + 1;
1495 if (prev && prev[0])
1496 return prev;
1497 }
1498 return NULL;
1499 }
1500
1501 /* This is seriously bogus, now that certs store their email addresses in
1502 ** subject Alternative Name extensions.
1503 ** Returns a string allocated by PORT_StrDup, which the caller must free.
1504 */
1505 char*
1506 CERT_GetCertEmailAddress(const CERTName* name)
1507 {
1508 char* rawEmailAddr;
1509 char* emailAddr;
1510
1511 rawEmailAddr = CERT_GetNameElement(NULL, name, SEC_OID_PKCS9_EMAIL_ADDRESS);
1512 if (rawEmailAddr == NULL) {
1513 rawEmailAddr = CERT_GetNameElement(NULL, name, SEC_OID_RFC1274_MAIL);
1514 }
1515 emailAddr = CERT_FixupEmailAddr(rawEmailAddr);
1516 if (rawEmailAddr) {
1517 PORT_Free(rawEmailAddr);
1518 }
1519 return (emailAddr);
1520 }
1521
1522 /* The return value must be freed with PORT_Free. */
1523 char*
1524 CERT_GetCommonName(const CERTName* name)
1525 {
1526 return (CERT_GetLastNameElement(NULL, name, SEC_OID_AVA_COMMON_NAME));
1527 }
1528
1529 char*
1530 CERT_GetCountryName(const CERTName* name)
1531 {
1532 return (CERT_GetNameElement(NULL, name, SEC_OID_AVA_COUNTRY_NAME));
1533 }
1534
1535 char*
1536 CERT_GetLocalityName(const CERTName* name)
1537 {
1538 return (CERT_GetNameElement(NULL, name, SEC_OID_AVA_LOCALITY));
1539 }
1540
1541 char*
1542 CERT_GetStateName(const CERTName* name)
1543 {
1544 return (CERT_GetNameElement(NULL, name, SEC_OID_AVA_STATE_OR_PROVINCE));
1545 }
1546
1547 char*
1548 CERT_GetOrgName(const CERTName* name)
1549 {
1550 return (CERT_GetNameElement(NULL, name, SEC_OID_AVA_ORGANIZATION_NAME));
1551 }
1552
1553 char*
1554 CERT_GetDomainComponentName(const CERTName* name)
1555 {
1556 return (CERT_GetNameElement(NULL, name, SEC_OID_AVA_DC));
1557 }
1558
1559 char*
1560 CERT_GetOrgUnitName(const CERTName* name)
1561 {
1562 return (
1563 CERT_GetNameElement(NULL, name, SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME));
1564 }
1565
1566 char*
1567 CERT_GetDnQualifier(const CERTName* name)
1568 {
1569 return (CERT_GetNameElement(NULL, name, SEC_OID_AVA_DN_QUALIFIER));
1570 }
1571
1572 char*
1573 CERT_GetCertUid(const CERTName* name)
1574 {
1575 return (CERT_GetNameElement(NULL, name, SEC_OID_RFC1274_UID));
1576 }
OLDNEW
« no previous file with comments | « nss/lib/base/tracker.c ('k') | nss/lib/certdb/cert.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698