Bug 460926 A11y hierachy is broken on Ubuntu 8.10 (GNOME 2.24), r=Evan.Yan sr=roc
[wine-gecko.git] / security / nss / lib / certdb / alg1485.c
blob739254cd94b8080626224305b3896f461e2777c6
1 /* alg1485.c - implementation of RFCs 1485, 1779 and 2253.
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is the Netscape security libraries.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1994-2000
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "prprf.h"
40 #include "cert.h"
41 #include "certi.h"
42 #include "xconst.h"
43 #include "genname.h"
44 #include "secitem.h"
45 #include "secerr.h"
47 typedef struct NameToKindStr {
48 const char * name;
49 unsigned int maxLen; /* max bytes in UTF8 encoded string value */
50 SECOidTag kind;
51 int valueType;
52 } NameToKind;
54 /* local type for directory string--could be printable_string or utf8 */
55 #define SEC_ASN1_DS SEC_ASN1_HIGH_TAG_NUMBER
57 /* Add new entries to this table, and maybe to function CERT_ParseRFC1485AVA */
58 static const NameToKind name2kinds[] = {
59 /* IANA registered type names
60 * (See: http://www.iana.org/assignments/ldap-parameters)
62 /* RFC 3280, 4630 MUST SUPPORT */
63 { "CN", 64, SEC_OID_AVA_COMMON_NAME, SEC_ASN1_DS},
64 { "ST", 128, SEC_OID_AVA_STATE_OR_PROVINCE,
65 SEC_ASN1_DS},
66 { "O", 64, SEC_OID_AVA_ORGANIZATION_NAME,
67 SEC_ASN1_DS},
68 { "OU", 64, SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME,
69 SEC_ASN1_DS},
70 { "dnQualifier", 32767, SEC_OID_AVA_DN_QUALIFIER, SEC_ASN1_PRINTABLE_STRING},
71 { "C", 2, SEC_OID_AVA_COUNTRY_NAME, SEC_ASN1_PRINTABLE_STRING},
72 { "serialNumber", 64, SEC_OID_AVA_SERIAL_NUMBER,SEC_ASN1_PRINTABLE_STRING},
74 /* RFC 3280, 4630 SHOULD SUPPORT */
75 { "L", 128, SEC_OID_AVA_LOCALITY, SEC_ASN1_DS},
76 { "title", 64, SEC_OID_AVA_TITLE, SEC_ASN1_DS},
77 { "SN", 64, SEC_OID_AVA_SURNAME, SEC_ASN1_DS},
78 { "givenName", 64, SEC_OID_AVA_GIVEN_NAME, SEC_ASN1_DS},
79 { "initials", 64, SEC_OID_AVA_INITIALS, SEC_ASN1_DS},
80 { "generationQualifier",
81 64, SEC_OID_AVA_GENERATION_QUALIFIER,
82 SEC_ASN1_DS},
83 /* RFC 3280, 4630 MAY SUPPORT */
84 { "DC", 128, SEC_OID_AVA_DC, SEC_ASN1_IA5_STRING},
85 { "MAIL", 256, SEC_OID_RFC1274_MAIL, SEC_ASN1_IA5_STRING},
86 { "UID", 256, SEC_OID_RFC1274_UID, SEC_ASN1_DS},
88 /* ------------------ "strict" boundary ---------------------------------
89 * In strict mode, cert_NameToAscii does not encode any of the attributes
90 * below this line. The first SECOidTag below this line must be used to
91 * conditionally define the "endKind" in function AppendAVA() below.
92 * Most new attribute names should be added below this line.
93 * Maybe this line should be up higher? Say, after the 3280 MUSTs and
94 * before the 3280 SHOULDs?
97 /* values from draft-ietf-ldapbis-user-schema-05 (not in RFC 3280) */
98 { "postalAddress", 128, SEC_OID_AVA_POSTAL_ADDRESS, SEC_ASN1_DS},
99 { "postalCode", 40, SEC_OID_AVA_POSTAL_CODE, SEC_ASN1_DS},
100 { "postOfficeBox", 40, SEC_OID_AVA_POST_OFFICE_BOX,SEC_ASN1_DS},
101 { "houseIdentifier",64, SEC_OID_AVA_HOUSE_IDENTIFIER,SEC_ASN1_DS},
102 /* end of IANA registered type names */
104 /* legacy keywords */
105 { "E", 128, SEC_OID_PKCS9_EMAIL_ADDRESS,SEC_ASN1_DS},
107 #if 0 /* removed. Not yet in any IETF draft or RFC. */
108 { "pseudonym", 64, SEC_OID_AVA_PSEUDONYM, SEC_ASN1_DS},
109 #endif
111 { 0, 256, SEC_OID_UNKNOWN , 0},
114 #define C_DOUBLE_QUOTE '\042'
116 #define C_BACKSLASH '\134'
118 #define C_EQUAL '='
120 #define OPTIONAL_SPACE(c) \
121 (((c) == ' ') || ((c) == '\r') || ((c) == '\n'))
123 #define SPECIAL_CHAR(c) \
124 (((c) == ',') || ((c) == '=') || ((c) == C_DOUBLE_QUOTE) || \
125 ((c) == '\r') || ((c) == '\n') || ((c) == '+') || \
126 ((c) == '<') || ((c) == '>') || ((c) == '#') || \
127 ((c) == ';') || ((c) == C_BACKSLASH))
130 #define IS_PRINTABLE(c) \
131 ((((c) >= 'a') && ((c) <= 'z')) || \
132 (((c) >= 'A') && ((c) <= 'Z')) || \
133 (((c) >= '0') && ((c) <= '9')) || \
134 ((c) == ' ') || \
135 ((c) == '\'') || \
136 ((c) == '\050') || /* ( */ \
137 ((c) == '\051') || /* ) */ \
138 (((c) >= '+') && ((c) <= '/')) || /* + , - . / */ \
139 ((c) == ':') || \
140 ((c) == '=') || \
141 ((c) == '?'))
144 cert_AVAOidTagToMaxLen(SECOidTag tag)
146 const NameToKind *n2k = name2kinds;
148 while (n2k->kind != tag && n2k->kind != SEC_OID_UNKNOWN) {
149 ++n2k;
151 return (n2k->kind != SEC_OID_UNKNOWN) ? n2k->maxLen : -1;
154 static PRBool
155 IsPrintable(unsigned char *data, unsigned len)
157 unsigned char ch, *end;
159 end = data + len;
160 while (data < end) {
161 ch = *data++;
162 if (!IS_PRINTABLE(ch)) {
163 return PR_FALSE;
166 return PR_TRUE;
169 static void
170 skipSpace(char **pbp, char *endptr)
172 char *bp = *pbp;
173 while (bp < endptr && OPTIONAL_SPACE(*bp)) {
174 bp++;
176 *pbp = bp;
179 static SECStatus
180 scanTag(char **pbp, char *endptr, char *tagBuf, int tagBufSize)
182 char *bp, *tagBufp;
183 int taglen;
185 PORT_Assert(tagBufSize > 0);
187 /* skip optional leading space */
188 skipSpace(pbp, endptr);
189 if (*pbp == endptr) {
190 /* nothing left */
191 return SECFailure;
194 /* fill tagBuf */
195 taglen = 0;
196 bp = *pbp;
197 tagBufp = tagBuf;
198 while (bp < endptr && !OPTIONAL_SPACE(*bp) && (*bp != C_EQUAL)) {
199 if (++taglen >= tagBufSize) {
200 *pbp = bp;
201 return SECFailure;
203 *tagBufp++ = *bp++;
205 /* null-terminate tagBuf -- guaranteed at least one space left */
206 *tagBufp++ = 0;
207 *pbp = bp;
209 /* skip trailing spaces till we hit something - should be an equal sign */
210 skipSpace(pbp, endptr);
211 if (*pbp == endptr) {
212 /* nothing left */
213 return SECFailure;
215 if (**pbp != C_EQUAL) {
216 /* should be an equal sign */
217 return SECFailure;
219 /* skip over the equal sign */
220 (*pbp)++;
222 return SECSuccess;
225 static SECStatus
226 scanVal(char **pbp, char *endptr, char *valBuf, int valBufSize)
228 char *bp, *valBufp;
229 int vallen;
230 PRBool isQuoted;
232 PORT_Assert(valBufSize > 0);
234 /* skip optional leading space */
235 skipSpace(pbp, endptr);
236 if(*pbp == endptr) {
237 /* nothing left */
238 return SECFailure;
241 bp = *pbp;
243 /* quoted? */
244 if (*bp == C_DOUBLE_QUOTE) {
245 isQuoted = PR_TRUE;
246 /* skip over it */
247 bp++;
248 } else {
249 isQuoted = PR_FALSE;
252 valBufp = valBuf;
253 vallen = 0;
254 while (bp < endptr) {
255 char c = *bp;
256 if (c == C_BACKSLASH) {
257 /* escape character */
258 bp++;
259 if (bp >= endptr) {
260 /* escape charater must appear with paired char */
261 *pbp = bp;
262 return SECFailure;
264 } else if (c == '#' && bp == *pbp) {
265 /* ignore leading #, quotation not required for it. */
266 } else if (!isQuoted && SPECIAL_CHAR(c)) {
267 /* unescaped special and not within quoted value */
268 break;
269 } else if (c == C_DOUBLE_QUOTE) {
270 /* reached unescaped double quote */
271 break;
273 /* append character */
274 vallen++;
275 if (vallen >= valBufSize) {
276 *pbp = bp;
277 return SECFailure;
279 *valBufp++ = *bp++;
282 /* stip trailing spaces from unquoted values */
283 if (!isQuoted) {
284 if (valBufp > valBuf) {
285 valBufp--;
286 while ((valBufp > valBuf) && OPTIONAL_SPACE(*valBufp)) {
287 valBufp--;
289 valBufp++;
293 if (isQuoted) {
294 /* insist that we stopped on a double quote */
295 if (*bp != C_DOUBLE_QUOTE) {
296 *pbp = bp;
297 return SECFailure;
299 /* skip over the quote and skip optional space */
300 bp++;
301 skipSpace(&bp, endptr);
304 *pbp = bp;
306 if (valBufp == valBuf) {
307 /* empty value -- not allowed */
308 return SECFailure;
311 /* null-terminate valBuf -- guaranteed at least one space left */
312 *valBufp++ = 0;
314 return SECSuccess;
317 static const PRInt16 x2b[256] =
319 /* #0x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
320 /* #1x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
321 /* #2x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
322 /* #3x */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
323 /* #4x */ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
324 /* #5x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
325 /* #6x */ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
326 /* #7x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
327 /* #8x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
328 /* #9x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
329 /* #ax */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
330 /* #bx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
331 /* #cx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
332 /* #dx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
333 /* #ex */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
334 /* #fx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
337 /* Caller must set error code upon failure */
338 static SECStatus
339 hexToBin(PLArenaPool *pool, SECItem * destItem, const char * src, int len)
341 PRUint8 * dest;
343 destItem->data = NULL;
344 if (len <= 0 || (len & 1)) {
345 goto loser;
347 len >>= 1;
348 if (!SECITEM_AllocItem(pool, destItem, len))
349 goto loser;
350 dest = destItem->data;
351 for (; len > 0; len--, src += 2) {
352 PRInt16 bin = (x2b[(PRUint8)src[0]] << 4) | x2b[(PRUint8)src[1]];
353 if (bin < 0)
354 goto loser;
355 *dest++ = (PRUint8)bin;
357 return SECSuccess;
358 loser:
359 if (!pool)
360 SECITEM_FreeItem(destItem, PR_FALSE);
361 return SECFailure;
365 CERTAVA *
366 CERT_ParseRFC1485AVA(PRArenaPool *arena, char **pbp, char *endptr,
367 PRBool singleAVA)
369 CERTAVA *a;
370 const NameToKind *n2k;
371 char *bp;
372 int vt = -1;
373 int valLen;
374 SECOidTag kind = SEC_OID_UNKNOWN;
375 SECStatus rv = SECFailure;
376 SECItem derOid = { 0, NULL, 0 };
378 char tagBuf[32];
379 char valBuf[384];
381 PORT_Assert(arena);
382 if (scanTag(pbp, endptr, tagBuf, sizeof(tagBuf)) == SECFailure ||
383 scanVal(pbp, endptr, valBuf, sizeof(valBuf)) == SECFailure) {
384 goto loser;
387 /* insist that if we haven't finished we've stopped on a separator */
388 bp = *pbp;
389 if (bp < endptr) {
390 if (singleAVA || (*bp != ',' && *bp != ';')) {
391 *pbp = bp;
392 goto loser;
394 /* ok, skip over separator */
395 bp++;
397 *pbp = bp;
399 /* is this a dotted decimal OID attribute type ? */
400 if (!PL_strncasecmp("oid.", tagBuf, 4)) {
401 rv = SEC_StringToOID(arena, &derOid, tagBuf, strlen(tagBuf));
402 } else {
403 for (n2k = name2kinds; n2k->name; n2k++) {
404 SECOidData *oidrec;
405 if (PORT_Strcasecmp(n2k->name, tagBuf) == 0) {
406 kind = n2k->kind;
407 vt = n2k->valueType;
408 oidrec = SECOID_FindOIDByTag(kind);
409 if (oidrec == NULL)
410 goto loser;
411 derOid = oidrec->oid;
412 break;
416 if (kind == SEC_OID_UNKNOWN && rv != SECSuccess)
417 goto loser;
419 /* Is this a hex encoding of a DER attribute value ? */
420 if ('#' == valBuf[0]) {
421 /* convert attribute value from hex to binary */
422 SECItem derVal = { 0, NULL, 0};
423 valLen = PORT_Strlen(valBuf+1);
424 rv = hexToBin(arena, &derVal, valBuf + 1, valLen);
425 if (rv)
426 goto loser;
427 a = CERT_CreateAVAFromRaw(arena, &derOid, &derVal);
428 } else {
429 if (kind == SEC_OID_UNKNOWN)
430 goto loser;
431 valLen = PORT_Strlen(valBuf);
432 if (kind == SEC_OID_AVA_COUNTRY_NAME && valLen != 2)
433 goto loser;
434 if (vt == SEC_ASN1_PRINTABLE_STRING &&
435 !IsPrintable((unsigned char*) valBuf, valLen))
436 goto loser;
437 if (vt == SEC_ASN1_DS) {
438 /* RFC 4630: choose PrintableString or UTF8String */
439 if (IsPrintable((unsigned char*) valBuf, valLen))
440 vt = SEC_ASN1_PRINTABLE_STRING;
441 else
442 vt = SEC_ASN1_UTF8_STRING;
445 a = CERT_CreateAVA(arena, kind, vt, (char *)valBuf);
447 return a;
449 loser:
450 /* matched no kind -- invalid tag */
451 PORT_SetError(SEC_ERROR_INVALID_AVA);
452 return 0;
455 static CERTName *
456 ParseRFC1485Name(char *buf, int len)
458 SECStatus rv;
459 CERTName *name;
460 char *bp, *e;
461 CERTAVA *ava;
462 CERTRDN *rdn;
464 name = CERT_CreateName(NULL);
465 if (name == NULL) {
466 return NULL;
469 e = buf + len;
470 bp = buf;
471 while (bp < e) {
472 ava = CERT_ParseRFC1485AVA(name->arena, &bp, e, PR_FALSE);
473 if (ava == 0) goto loser;
474 rdn = CERT_CreateRDN(name->arena, ava, (CERTAVA *)0);
475 if (rdn == 0) goto loser;
476 rv = CERT_AddRDN(name, rdn);
477 if (rv) goto loser;
478 skipSpace(&bp, e);
481 if (name->rdns[0] == 0) {
482 /* empty name -- illegal */
483 goto loser;
486 /* Reverse order of RDNS to comply with RFC */
488 CERTRDN **firstRdn;
489 CERTRDN **lastRdn;
490 CERTRDN *tmp;
492 /* get first one */
493 firstRdn = name->rdns;
495 /* find last one */
496 lastRdn = name->rdns;
497 while (*lastRdn) lastRdn++;
498 lastRdn--;
500 /* reverse list */
501 for ( ; firstRdn < lastRdn; firstRdn++, lastRdn--) {
502 tmp = *firstRdn;
503 *firstRdn = *lastRdn;
504 *lastRdn = tmp;
508 /* return result */
509 return name;
511 loser:
512 CERT_DestroyName(name);
513 return NULL;
516 CERTName *
517 CERT_AsciiToName(char *string)
519 CERTName *name;
520 name = ParseRFC1485Name(string, PORT_Strlen(string));
521 return name;
524 /************************************************************************/
526 typedef struct stringBufStr {
527 char *buffer;
528 unsigned offset;
529 unsigned size;
530 } stringBuf;
532 #define DEFAULT_BUFFER_SIZE 200
534 static SECStatus
535 AppendStr(stringBuf *bufp, char *str)
537 char *buf;
538 unsigned bufLen, bufSize, len;
539 int size = 0;
541 /* Figure out how much to grow buf by (add in the '\0') */
542 buf = bufp->buffer;
543 bufLen = bufp->offset;
544 len = PORT_Strlen(str);
545 bufSize = bufLen + len;
546 if (!buf) {
547 bufSize++;
548 size = PR_MAX(DEFAULT_BUFFER_SIZE,bufSize*2);
549 buf = (char *) PORT_Alloc(size);
550 bufp->size = size;
551 } else if (bufp->size < bufSize) {
552 size = bufSize*2;
553 buf =(char *) PORT_Realloc(buf,size);
554 bufp->size = size;
556 if (!buf) {
557 PORT_SetError(SEC_ERROR_NO_MEMORY);
558 return SECFailure;
560 bufp->buffer = buf;
561 bufp->offset = bufSize;
563 /* Concatenate str onto buf */
564 buf = buf + bufLen;
565 if (bufLen) buf--; /* stomp on old '\0' */
566 PORT_Memcpy(buf, str, len+1); /* put in new null */
567 return SECSuccess;
570 static int
571 cert_RFC1485_GetRequiredLen(const char *src, int srclen, PRBool *pNeedsQuoting)
573 int i, reqLen=0;
574 PRBool needsQuoting = PR_FALSE;
575 char lastC = 0;
577 /* need to make an initial pass to determine if quoting is needed */
578 for (i = 0; i < srclen; i++) {
579 char c = src[i];
580 reqLen++;
581 if (!needsQuoting && (SPECIAL_CHAR(c) ||
582 (OPTIONAL_SPACE(c) && OPTIONAL_SPACE(lastC)))) {
583 /* entirety will need quoting */
584 needsQuoting = PR_TRUE;
586 if (c == C_DOUBLE_QUOTE || c == C_BACKSLASH) {
587 /* this char will need escaping */
588 reqLen++;
590 lastC = c;
592 /* if it begins or ends in optional space it needs quoting */
593 if (!needsQuoting && srclen > 0 &&
594 (OPTIONAL_SPACE(src[srclen-1]) || OPTIONAL_SPACE(src[0]))) {
595 needsQuoting = PR_TRUE;
598 if (needsQuoting)
599 reqLen += 2;
600 if (pNeedsQuoting)
601 *pNeedsQuoting = needsQuoting;
603 return reqLen;
606 SECStatus
607 CERT_RFC1485_EscapeAndQuote(char *dst, int dstlen, char *src, int srclen)
609 int i, reqLen=0;
610 char *d = dst;
611 PRBool needsQuoting = PR_FALSE;
613 /* space for terminal null */
614 reqLen = cert_RFC1485_GetRequiredLen(src, srclen, &needsQuoting) + 1;
615 if (reqLen > dstlen) {
616 PORT_SetError(SEC_ERROR_OUTPUT_LEN);
617 return SECFailure;
620 d = dst;
621 if (needsQuoting) *d++ = C_DOUBLE_QUOTE;
622 for (i = 0; i < srclen; i++) {
623 char c = src[i];
624 if (c == C_DOUBLE_QUOTE || c == C_BACKSLASH) {
625 /* escape it */
626 *d++ = C_BACKSLASH;
628 *d++ = c;
630 if (needsQuoting) *d++ = C_DOUBLE_QUOTE;
631 *d++ = 0;
632 return SECSuccess;
635 /* convert an OID to dotted-decimal representation */
636 /* Returns a string that must be freed with PR_smprintf_free(), */
637 char *
638 CERT_GetOidString(const SECItem *oid)
640 PRUint8 *end;
641 PRUint8 *d;
642 PRUint8 *e;
643 char *a = NULL;
644 char *b;
646 #define MAX_OID_LEN 1024 /* bytes */
648 if (oid->len > MAX_OID_LEN) {
649 PORT_SetError(SEC_ERROR_INPUT_LEN);
650 return NULL;
653 /* d will point to the next sequence of bytes to decode */
654 d = (PRUint8 *)oid->data;
655 /* end points to one past the legitimate data */
656 end = &d[ oid->len ];
659 * Check for our pseudo-encoded single-digit OIDs
661 if( (*d == 0x80) && (2 == oid->len) ) {
662 /* Funky encoding. The second byte is the number */
663 a = PR_smprintf("%lu", (PRUint32)d[1]);
664 if( (char *)NULL == a ) {
665 PORT_SetError(SEC_ERROR_NO_MEMORY);
666 return (char *)NULL;
668 return a;
671 for( ; d < end; d = &e[1] ) {
673 for( e = d; e < end; e++ ) {
674 if( 0 == (*e & 0x80) ) {
675 break;
679 if( ((e-d) > 4) || (((e-d) == 4) && (*d & 0x70)) ) {
680 /* More than a 32-bit number */
681 } else {
682 PRUint32 n = 0;
684 switch( e-d ) {
685 case 4:
686 n |= ((PRUint32)(e[-4] & 0x0f)) << 28;
687 case 3:
688 n |= ((PRUint32)(e[-3] & 0x7f)) << 21;
689 case 2:
690 n |= ((PRUint32)(e[-2] & 0x7f)) << 14;
691 case 1:
692 n |= ((PRUint32)(e[-1] & 0x7f)) << 7;
693 case 0:
694 n |= ((PRUint32)(e[-0] & 0x7f)) ;
697 if( (char *)NULL == a ) {
698 /* This is the first number.. decompose it */
699 PRUint32 one = PR_MIN(n/40, 2); /* never > 2 */
700 PRUint32 two = n - one * 40;
702 a = PR_smprintf("OID.%lu.%lu", one, two);
703 if( (char *)NULL == a ) {
704 PORT_SetError(SEC_ERROR_NO_MEMORY);
705 return (char *)NULL;
707 } else {
708 b = PR_smprintf("%s.%lu", a, n);
709 if( (char *)NULL == b ) {
710 PR_smprintf_free(a);
711 PORT_SetError(SEC_ERROR_NO_MEMORY);
712 return (char *)NULL;
715 PR_smprintf_free(a);
716 a = b;
721 return a;
724 /* convert DER-encoded hex to a string */
725 static SECItem *
726 get_hex_string(SECItem *data)
728 SECItem *rv;
729 unsigned int i, j;
730 static const char hex[] = { "0123456789ABCDEF" };
732 /* '#' + 2 chars per octet + terminator */
733 rv = SECITEM_AllocItem(NULL, NULL, data->len*2 + 2);
734 if (!rv) {
735 return NULL;
737 rv->data[0] = '#';
738 rv->len = 1 + 2 * data->len;
739 for (i=0; i<data->len; i++) {
740 j = data->data[i];
741 rv->data[2*i+1] = hex[j >> 4];
742 rv->data[2*i+2] = hex[j & 15];
744 rv->data[rv->len] = 0;
745 return rv;
748 /* For compliance with RFC 2253, RFC 3280 and RFC 4630, we choose to
749 * use the NAME=STRING form, rather than the OID.N.N=#hexXXXX form,
750 * when both of these conditions are met:
751 * 1) The attribute name OID (kind) has a known name string that is
752 * defined in one of those RFCs, or in RFCs that they cite, AND
753 * 2) The attribute's value encoding is RFC compliant for the kind
754 * (e.g., the value's encoding tag is correct for the kind, and
755 * the value's length is in the range allowed for the kind, and
756 * the value's contents are appropriate for the encoding tag).
757 * Otherwise, we use the OID.N.N=#hexXXXX form.
759 * If the caller prefers maximum human readability to RFC compliance,
760 * then
761 * - We print the kind in NAME= string form if we know the name
762 * string for the attribute type OID, regardless of whether the
763 * value is correctly encoded or not. else we use the OID.N.N= form.
764 * - We use the non-hex STRING form for the attribute value if the
765 * value can be represented in such a form. Otherwise, we use
766 * the hex string form.
767 * This implies that, for maximum human readability, in addition to
768 * the two forms allowed by the RFC, we allow two other forms of output:
769 * - the OID.N.N=STRING form, and
770 * - the NAME=#hexXXXX form
771 * When the caller prefers maximum human readability, we do not allow
772 * the value of any attribute to exceed the length allowed by the RFC.
773 * If the attribute value exceeds the allowed length, we truncate it to
774 * the allowed length and append "...".
775 * Also in this case, we arbitrarily impose a limit on the length of the
776 * entire AVA encoding, regardless of the form, of 384 bytes per AVA.
777 * This limit includes the trailing NULL character. If the encoded
778 * AVA length exceeds that limit, this function reports failure to encode
779 * the AVA.
781 * An ASCII representation of an AVA is said to be "invertible" if
782 * conversion back to DER reproduces the original DER encoding exactly.
783 * The RFC 2253 rules do not ensure that all ASCII AVAs derived according
784 * to its rules are invertible. That is because the RFCs allow some
785 * attribute values to be encoded in any of a number of encodings,
786 * and the encoding type information is lost in the non-hex STRING form.
787 * This is particularly true of attributes of type DirectoryString.
788 * The encoding type information is always preserved in the hex string
789 * form, because the hex includes the entire DER encoding of the value.
791 * So, when the caller perfers maximum invertibility, we apply the
792 * RFC compliance rules stated above, and add a third required
793 * condition on the use of the NAME=STRING form.
794 * 3) The attribute's kind is not is allowed to be encoded in any of
795 * several different encodings, such as DirectoryStrings.
797 * The chief difference between CERT_N2A_STRICT and CERT_N2A_INVERTIBLE
798 * is that the latter forces DirectoryStrings to be hex encoded.
800 * As a simplification, we assume the value is correctly encoded for
801 * its encoding type. That is, we do not test that all the characters
802 * in a string encoded type are allowed by that type. We assume it.
804 static SECStatus
805 AppendAVA(stringBuf *bufp, CERTAVA *ava, CertStrictnessLevel strict)
807 const NameToKind *pn2k = name2kinds;
808 SECItem *avaValue = NULL;
809 char *unknownTag = NULL;
810 char *encodedAVA = NULL;
811 PRBool useHex = PR_FALSE; /* use =#hexXXXX form */
812 SECOidTag endKind;
813 SECStatus rv;
814 unsigned int len;
815 int nameLen, valueLen;
816 NameToKind n2k = { NULL, 32767, SEC_OID_UNKNOWN, SEC_ASN1_DS };
817 char tmpBuf[384];
819 #define tagName n2k.name /* non-NULL means use NAME= form */
820 #define maxBytes n2k.maxLen
821 #define tag n2k.kind
822 #define vt n2k.valueType
824 /* READABLE mode recognizes more names from the name2kinds table
825 * than do STRICT or INVERTIBLE modes. This assignment chooses the
826 * point in the table where the attribute type name scanning stops.
828 endKind = (strict == CERT_N2A_READABLE) ? SEC_OID_UNKNOWN
829 : SEC_OID_AVA_POSTAL_ADDRESS;
830 tag = CERT_GetAVATag(ava);
831 while (pn2k->kind != tag && pn2k->kind != endKind) {
832 ++pn2k;
835 if (pn2k->kind != endKind ) {
836 n2k = *pn2k;
837 } else if (strict != CERT_N2A_READABLE) {
838 useHex = PR_TRUE;
840 /* For invertable form, force Directory Strings to use hex form. */
841 if (strict == CERT_N2A_INVERTIBLE && vt == SEC_ASN1_DS) {
842 tagName = NULL; /* must use OID.N form */
843 useHex = PR_TRUE; /* must use hex string */
845 if (!useHex) {
846 avaValue = CERT_DecodeAVAValue(&ava->value);
847 if (!avaValue) {
848 useHex = PR_TRUE;
849 if (strict != CERT_N2A_READABLE) {
850 tagName = NULL; /* must use OID.N form */
854 if (!tagName) {
855 /* handle unknown attribute types per RFC 2253 */
856 tagName = unknownTag = CERT_GetOidString(&ava->type);
857 if (!tagName) {
858 if (avaValue)
859 SECITEM_FreeItem(avaValue, PR_TRUE);
860 return SECFailure;
863 if (useHex) {
864 avaValue = get_hex_string(&ava->value);
865 if (!avaValue) {
866 if (unknownTag)
867 PR_smprintf_free(unknownTag);
868 return SECFailure;
872 if (strict == CERT_N2A_READABLE) {
873 if (maxBytes > sizeof(tmpBuf) - 4)
874 maxBytes = sizeof(tmpBuf) - 4;
875 /* Check value length. Must be room for "..." */
876 if (avaValue->len > maxBytes + 3) {
877 /* avaValue is a UTF8 string, freshly allocated and returned to us
878 ** by CERT_DecodeAVAValue or get_hex_string just above, so we can
879 ** modify it here. See if we're in the middle of a multi-byte
880 ** UTF8 character.
882 len = maxBytes;
883 while (((avaValue->data[len] & 0xc0) == 0x80) && len > 0) {
884 len--;
886 /* add elipsis to signify truncation. */
887 avaValue->data[len++] = '.';
888 avaValue->data[len++] = '.';
889 avaValue->data[len++] = '.';
890 avaValue->data[len] = 0;
891 avaValue->len = len;
895 nameLen = strlen(tagName);
896 valueLen = (useHex ? avaValue->len :
897 cert_RFC1485_GetRequiredLen(avaValue->data, avaValue->len, NULL));
898 len = nameLen + valueLen + 2; /* Add 2 for '=' and trailing NUL */
900 if (len <= sizeof(tmpBuf)) {
901 encodedAVA = tmpBuf;
902 } else if (strict == CERT_N2A_READABLE) {
903 PORT_SetError(SEC_ERROR_OUTPUT_LEN);
904 } else {
905 encodedAVA = PORT_Alloc(len);
907 if (!encodedAVA) {
908 SECITEM_FreeItem(avaValue, PR_TRUE);
909 if (unknownTag)
910 PR_smprintf_free(unknownTag);
911 return SECFailure;
913 memcpy(encodedAVA, tagName, nameLen);
914 if (unknownTag)
915 PR_smprintf_free(unknownTag);
916 encodedAVA[nameLen++] = '=';
918 /* escape and quote as necessary - don't quote hex strings */
919 if (useHex) {
920 memcpy(encodedAVA + nameLen, (char *)avaValue->data, avaValue->len);
921 encodedAVA[nameLen + avaValue->len] = '\0';
922 rv = SECSuccess;
923 } else
924 rv = CERT_RFC1485_EscapeAndQuote(encodedAVA + nameLen, len - nameLen,
925 (char *)avaValue->data, avaValue->len);
926 SECITEM_FreeItem(avaValue, PR_TRUE);
927 if (rv == SECSuccess)
928 rv = AppendStr(bufp, encodedAVA);
929 if (encodedAVA != tmpBuf)
930 PORT_Free(encodedAVA);
931 return rv;
934 #undef tagName
935 #undef maxBytes
936 #undef tag
937 #undef vt
939 char *
940 CERT_NameToAsciiInvertible(CERTName *name, CertStrictnessLevel strict)
942 CERTRDN** rdns;
943 CERTRDN** lastRdn;
944 CERTRDN** rdn;
945 PRBool first = PR_TRUE;
946 stringBuf strBuf = { NULL, 0, 0 };
948 rdns = name->rdns;
949 if (rdns == NULL) {
950 return NULL;
953 /* find last RDN */
954 lastRdn = rdns;
955 while (*lastRdn) lastRdn++;
956 lastRdn--;
959 * Loop over name contents in _reverse_ RDN order appending to string
961 for (rdn = lastRdn; rdn >= rdns; rdn--) {
962 CERTAVA** avas = (*rdn)->avas;
963 CERTAVA* ava;
964 PRBool newRDN = PR_TRUE;
967 * XXX Do we need to traverse the AVAs in reverse order, too?
969 while (avas && (ava = *avas++) != NULL) {
970 SECStatus rv;
971 /* Put in comma or plus separator */
972 if (!first) {
973 /* Use of spaces is deprecated in RFC 2253. */
974 rv = AppendStr(&strBuf, newRDN ? "," : "+");
975 if (rv) goto loser;
976 } else {
977 first = PR_FALSE;
980 /* Add in tag type plus value into buf */
981 rv = AppendAVA(&strBuf, ava, strict);
982 if (rv) goto loser;
983 newRDN = PR_FALSE;
986 return strBuf.buffer;
987 loser:
988 if (strBuf.buffer) {
989 PORT_Free(strBuf.buffer);
991 return NULL;
994 char *
995 CERT_NameToAscii(CERTName *name)
997 return CERT_NameToAsciiInvertible(name, CERT_N2A_READABLE);
1001 * Return the string representation of a DER encoded distinguished name
1002 * "dername" - The DER encoded name to convert
1004 char *
1005 CERT_DerNameToAscii(SECItem *dername)
1007 int rv;
1008 PRArenaPool *arena = NULL;
1009 CERTName name;
1010 char *retstr = NULL;
1012 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1014 if ( arena == NULL) {
1015 goto loser;
1018 rv = SEC_QuickDERDecodeItem(arena, &name, CERT_NameTemplate, dername);
1020 if ( rv != SECSuccess ) {
1021 goto loser;
1024 retstr = CERT_NameToAscii(&name);
1026 loser:
1027 if ( arena != NULL ) {
1028 PORT_FreeArena(arena, PR_FALSE);
1031 return(retstr);
1034 /* RDNs are sorted from most general to most specific.
1035 * This code returns the FIRST one found, the most general one found.
1037 static char *
1038 CERT_GetNameElement(PRArenaPool *arena, CERTName *name, int wantedTag)
1040 CERTRDN** rdns;
1041 CERTRDN *rdn;
1042 char *buf = 0;
1044 rdns = name->rdns;
1045 while (rdns && (rdn = *rdns++) != 0) {
1046 CERTAVA** avas = rdn->avas;
1047 CERTAVA* ava;
1048 while (avas && (ava = *avas++) != 0) {
1049 int tag = CERT_GetAVATag(ava);
1050 if ( tag == wantedTag ) {
1051 SECItem *decodeItem = CERT_DecodeAVAValue(&ava->value);
1052 if(!decodeItem) {
1053 return NULL;
1055 if (arena) {
1056 buf = (char *)PORT_ArenaZAlloc(arena,decodeItem->len + 1);
1057 } else {
1058 buf = (char *)PORT_ZAlloc(decodeItem->len + 1);
1060 if ( buf ) {
1061 PORT_Memcpy(buf, decodeItem->data, decodeItem->len);
1062 buf[decodeItem->len] = 0;
1064 SECITEM_FreeItem(decodeItem, PR_TRUE);
1065 goto done;
1070 done:
1071 return buf;
1074 /* RDNs are sorted from most general to most specific.
1075 * This code returns the LAST one found, the most specific one found.
1076 * This is particularly appropriate for Common Name. See RFC 2818.
1078 static char *
1079 CERT_GetLastNameElement(PRArenaPool *arena, CERTName *name, int wantedTag)
1081 CERTRDN** rdns;
1082 CERTRDN *rdn;
1083 CERTAVA * lastAva = NULL;
1084 char *buf = 0;
1086 rdns = name->rdns;
1087 while (rdns && (rdn = *rdns++) != 0) {
1088 CERTAVA** avas = rdn->avas;
1089 CERTAVA* ava;
1090 while (avas && (ava = *avas++) != 0) {
1091 int tag = CERT_GetAVATag(ava);
1092 if ( tag == wantedTag ) {
1093 lastAva = ava;
1098 if (lastAva) {
1099 SECItem *decodeItem = CERT_DecodeAVAValue(&lastAva->value);
1100 if(!decodeItem) {
1101 return NULL;
1103 if (arena) {
1104 buf = (char *)PORT_ArenaZAlloc(arena,decodeItem->len + 1);
1105 } else {
1106 buf = (char *)PORT_ZAlloc(decodeItem->len + 1);
1108 if ( buf ) {
1109 PORT_Memcpy(buf, decodeItem->data, decodeItem->len);
1110 buf[decodeItem->len] = 0;
1112 SECITEM_FreeItem(decodeItem, PR_TRUE);
1114 return buf;
1117 char *
1118 CERT_GetCertificateEmailAddress(CERTCertificate *cert)
1120 char *rawEmailAddr = NULL;
1121 SECItem subAltName;
1122 SECStatus rv;
1123 CERTGeneralName *nameList = NULL;
1124 CERTGeneralName *current;
1125 PRArenaPool *arena = NULL;
1126 int i;
1128 subAltName.data = NULL;
1130 rawEmailAddr = CERT_GetNameElement(cert->arena, &(cert->subject),
1131 SEC_OID_PKCS9_EMAIL_ADDRESS);
1132 if ( rawEmailAddr == NULL ) {
1133 rawEmailAddr = CERT_GetNameElement(cert->arena, &(cert->subject),
1134 SEC_OID_RFC1274_MAIL);
1136 if ( rawEmailAddr == NULL) {
1138 rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME,
1139 &subAltName);
1140 if (rv != SECSuccess) {
1141 goto finish;
1143 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1144 if (!arena) {
1145 goto finish;
1147 nameList = current = CERT_DecodeAltNameExtension(arena, &subAltName);
1148 if (!nameList ) {
1149 goto finish;
1151 if (nameList != NULL) {
1152 do {
1153 if (current->type == certDirectoryName) {
1154 rawEmailAddr = CERT_GetNameElement(cert->arena,
1155 &(current->name.directoryName),
1156 SEC_OID_PKCS9_EMAIL_ADDRESS);
1157 if ( rawEmailAddr == NULL ) {
1158 rawEmailAddr = CERT_GetNameElement(cert->arena,
1159 &(current->name.directoryName), SEC_OID_RFC1274_MAIL);
1161 } else if (current->type == certRFC822Name) {
1162 rawEmailAddr = (char*)PORT_ArenaZAlloc(cert->arena,
1163 current->name.other.len + 1);
1164 if (!rawEmailAddr) {
1165 goto finish;
1167 PORT_Memcpy(rawEmailAddr, current->name.other.data,
1168 current->name.other.len);
1169 rawEmailAddr[current->name.other.len] = '\0';
1171 if (rawEmailAddr) {
1172 break;
1174 current = CERT_GetNextGeneralName(current);
1175 } while (current != nameList);
1178 if (rawEmailAddr) {
1179 for (i = 0; i <= (int) PORT_Strlen(rawEmailAddr); i++) {
1180 rawEmailAddr[i] = tolower(rawEmailAddr[i]);
1184 finish:
1186 /* Don't free nameList, it's part of the arena. */
1188 if (arena) {
1189 PORT_FreeArena(arena, PR_FALSE);
1192 if ( subAltName.data ) {
1193 SECITEM_FreeItem(&subAltName, PR_FALSE);
1196 return(rawEmailAddr);
1199 static char *
1200 appendStringToBuf(char *dest, char *src, PRUint32 *pRemaining)
1202 PRUint32 len;
1203 if (dest && src && src[0] && *pRemaining > (len = PL_strlen(src))) {
1204 PRUint32 i;
1205 for (i = 0; i < len; ++i)
1206 dest[i] = tolower(src[i]);
1207 dest[len] = 0;
1208 dest += len + 1;
1209 *pRemaining -= len + 1;
1211 return dest;
1214 static char *
1215 appendItemToBuf(char *dest, SECItem *src, PRUint32 *pRemaining)
1217 if (dest && src && src->data && src->len && src->data[0] &&
1218 *pRemaining > src->len + 1 ) {
1219 PRUint32 len = src->len;
1220 PRUint32 i;
1221 for (i = 0; i < len && src->data[i] ; ++i)
1222 dest[i] = tolower(src->data[i]);
1223 dest[len] = 0;
1224 dest += len + 1;
1225 *pRemaining -= len + 1;
1227 return dest;
1230 /* Returns a pointer to an environment-like string, a series of
1231 ** null-terminated strings, terminated by a zero-length string.
1232 ** This function is intended to be internal to NSS.
1234 char *
1235 cert_GetCertificateEmailAddresses(CERTCertificate *cert)
1237 char * rawEmailAddr = NULL;
1238 char * addrBuf = NULL;
1239 char * pBuf = NULL;
1240 PRArenaPool * tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1241 PRUint32 maxLen = 0;
1242 PRInt32 finalLen = 0;
1243 SECStatus rv;
1244 SECItem subAltName;
1246 if (!tmpArena)
1247 return addrBuf;
1249 subAltName.data = NULL;
1250 maxLen = cert->derCert.len;
1251 PORT_Assert(maxLen);
1252 if (!maxLen)
1253 maxLen = 2000; /* a guess, should never happen */
1255 pBuf = addrBuf = (char *)PORT_ArenaZAlloc(tmpArena, maxLen + 1);
1256 if (!addrBuf)
1257 goto loser;
1259 rawEmailAddr = CERT_GetNameElement(tmpArena, &cert->subject,
1260 SEC_OID_PKCS9_EMAIL_ADDRESS);
1261 pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
1263 rawEmailAddr = CERT_GetNameElement(tmpArena, &cert->subject,
1264 SEC_OID_RFC1274_MAIL);
1265 pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
1267 rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME,
1268 &subAltName);
1269 if (rv == SECSuccess && subAltName.data) {
1270 CERTGeneralName *nameList = NULL;
1272 if (!!(nameList = CERT_DecodeAltNameExtension(tmpArena, &subAltName))) {
1273 CERTGeneralName *current = nameList;
1274 do {
1275 if (current->type == certDirectoryName) {
1276 rawEmailAddr = CERT_GetNameElement(tmpArena,
1277 &current->name.directoryName,
1278 SEC_OID_PKCS9_EMAIL_ADDRESS);
1279 pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
1281 rawEmailAddr = CERT_GetNameElement(tmpArena,
1282 &current->name.directoryName,
1283 SEC_OID_RFC1274_MAIL);
1284 pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
1285 } else if (current->type == certRFC822Name) {
1286 pBuf = appendItemToBuf(pBuf, &current->name.other, &maxLen);
1288 current = CERT_GetNextGeneralName(current);
1289 } while (current != nameList);
1291 SECITEM_FreeItem(&subAltName, PR_FALSE);
1292 /* Don't free nameList, it's part of the tmpArena. */
1294 /* now copy superstring to cert's arena */
1295 finalLen = (pBuf - addrBuf) + 1;
1296 pBuf = NULL;
1297 if (finalLen > 1) {
1298 pBuf = PORT_ArenaAlloc(cert->arena, finalLen);
1299 if (pBuf) {
1300 PORT_Memcpy(pBuf, addrBuf, finalLen);
1303 loser:
1304 if (tmpArena)
1305 PORT_FreeArena(tmpArena, PR_FALSE);
1307 return pBuf;
1310 /* returns pointer to storage in cert's arena. Storage remains valid
1311 ** as long as cert's reference count doesn't go to zero.
1312 ** Caller should strdup or otherwise copy.
1314 const char * /* const so caller won't muck with it. */
1315 CERT_GetFirstEmailAddress(CERTCertificate * cert)
1317 if (cert && cert->emailAddr && cert->emailAddr[0])
1318 return (const char *)cert->emailAddr;
1319 return NULL;
1322 /* returns pointer to storage in cert's arena. Storage remains valid
1323 ** as long as cert's reference count doesn't go to zero.
1324 ** Caller should strdup or otherwise copy.
1326 const char * /* const so caller won't muck with it. */
1327 CERT_GetNextEmailAddress(CERTCertificate * cert, const char * prev)
1329 if (cert && prev && prev[0]) {
1330 PRUint32 len = PL_strlen(prev);
1331 prev += len + 1;
1332 if (prev && prev[0])
1333 return prev;
1335 return NULL;
1338 /* This is seriously bogus, now that certs store their email addresses in
1339 ** subject Alternative Name extensions.
1340 ** Returns a string allocated by PORT_StrDup, which the caller must free.
1342 char *
1343 CERT_GetCertEmailAddress(CERTName *name)
1345 char *rawEmailAddr;
1346 char *emailAddr;
1349 rawEmailAddr = CERT_GetNameElement(NULL, name, SEC_OID_PKCS9_EMAIL_ADDRESS);
1350 if ( rawEmailAddr == NULL ) {
1351 rawEmailAddr = CERT_GetNameElement(NULL, name, SEC_OID_RFC1274_MAIL);
1353 emailAddr = CERT_FixupEmailAddr(rawEmailAddr);
1354 if ( rawEmailAddr ) {
1355 PORT_Free(rawEmailAddr);
1357 return(emailAddr);
1360 /* The return value must be freed with PORT_Free. */
1361 char *
1362 CERT_GetCommonName(CERTName *name)
1364 return(CERT_GetLastNameElement(NULL, name, SEC_OID_AVA_COMMON_NAME));
1367 char *
1368 CERT_GetCountryName(CERTName *name)
1370 return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_COUNTRY_NAME));
1373 char *
1374 CERT_GetLocalityName(CERTName *name)
1376 return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_LOCALITY));
1379 char *
1380 CERT_GetStateName(CERTName *name)
1382 return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_STATE_OR_PROVINCE));
1385 char *
1386 CERT_GetOrgName(CERTName *name)
1388 return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_ORGANIZATION_NAME));
1391 char *
1392 CERT_GetDomainComponentName(CERTName *name)
1394 return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_DC));
1397 char *
1398 CERT_GetOrgUnitName(CERTName *name)
1400 return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME));
1403 char *
1404 CERT_GetDnQualifier(CERTName *name)
1406 return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_DN_QUALIFIER));
1409 char *
1410 CERT_GetCertUid(CERTName *name)
1412 return(CERT_GetNameElement(NULL, name, SEC_OID_RFC1274_UID));