security/nss/lib/certdb/alg1485.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial