security/nss/lib/certdb/alg1485.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/certdb/alg1485.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1560 @@
     1.4 +/* alg1485.c - implementation of RFCs 1485, 1779 and 2253.
     1.5 + *
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "prprf.h"
    1.11 +#include "cert.h"
    1.12 +#include "certi.h"
    1.13 +#include "xconst.h"
    1.14 +#include "genname.h"
    1.15 +#include "secitem.h"
    1.16 +#include "secerr.h"
    1.17 +
    1.18 +typedef struct NameToKindStr {
    1.19 +    const char * name;
    1.20 +    unsigned int maxLen; /* max bytes in UTF8 encoded string value */
    1.21 +    SECOidTag    kind;
    1.22 +    int		 valueType;
    1.23 +} NameToKind;
    1.24 +
    1.25 +/* local type for directory string--could be printable_string or utf8 */
    1.26 +#define SEC_ASN1_DS SEC_ASN1_HIGH_TAG_NUMBER
    1.27 +
    1.28 +/* Add new entries to this table, and maybe to function ParseRFC1485AVA */
    1.29 +static const NameToKind name2kinds[] = {
    1.30 +/* IANA registered type names
    1.31 + * (See: http://www.iana.org/assignments/ldap-parameters) 
    1.32 + */
    1.33 +/* RFC 3280, 4630 MUST SUPPORT */
    1.34 +    { "CN",            640, SEC_OID_AVA_COMMON_NAME,    SEC_ASN1_DS},
    1.35 +    { "ST",            128, SEC_OID_AVA_STATE_OR_PROVINCE,
    1.36 +							SEC_ASN1_DS},
    1.37 +    { "O",             128, SEC_OID_AVA_ORGANIZATION_NAME,
    1.38 +							SEC_ASN1_DS},
    1.39 +    { "OU",            128, SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME,
    1.40 +                                                        SEC_ASN1_DS},
    1.41 +    { "dnQualifier", 32767, SEC_OID_AVA_DN_QUALIFIER, SEC_ASN1_PRINTABLE_STRING},
    1.42 +    { "C",               2, SEC_OID_AVA_COUNTRY_NAME, SEC_ASN1_PRINTABLE_STRING},
    1.43 +    { "serialNumber",   64, SEC_OID_AVA_SERIAL_NUMBER,SEC_ASN1_PRINTABLE_STRING},
    1.44 +
    1.45 +/* RFC 3280, 4630 SHOULD SUPPORT */
    1.46 +    { "L",             128, SEC_OID_AVA_LOCALITY,       SEC_ASN1_DS},
    1.47 +    { "title",          64, SEC_OID_AVA_TITLE,          SEC_ASN1_DS},
    1.48 +    { "SN",             64, SEC_OID_AVA_SURNAME,        SEC_ASN1_DS},
    1.49 +    { "givenName",      64, SEC_OID_AVA_GIVEN_NAME,     SEC_ASN1_DS},
    1.50 +    { "initials",       64, SEC_OID_AVA_INITIALS,       SEC_ASN1_DS},
    1.51 +    { "generationQualifier",
    1.52 +                        64, SEC_OID_AVA_GENERATION_QUALIFIER,
    1.53 +                                                        SEC_ASN1_DS},
    1.54 +/* RFC 3280, 4630 MAY SUPPORT */
    1.55 +    { "DC",            128, SEC_OID_AVA_DC,             SEC_ASN1_IA5_STRING},
    1.56 +    { "MAIL",          256, SEC_OID_RFC1274_MAIL,       SEC_ASN1_IA5_STRING},
    1.57 +    { "UID",           256, SEC_OID_RFC1274_UID,        SEC_ASN1_DS},
    1.58 +
    1.59 +/* ------------------ "strict" boundary ---------------------------------
    1.60 + * In strict mode, cert_NameToAscii does not encode any of the attributes
    1.61 + * below this line. The first SECOidTag below this line must be used to
    1.62 + * conditionally define the "endKind" in function AppendAVA() below.
    1.63 + * Most new attribute names should be added below this line.
    1.64 + * Maybe this line should be up higher?  Say, after the 3280 MUSTs and 
    1.65 + * before the 3280 SHOULDs?
    1.66 + */
    1.67 +
    1.68 +/* values from draft-ietf-ldapbis-user-schema-05 (not in RFC 3280) */
    1.69 +    { "postalAddress", 128, SEC_OID_AVA_POSTAL_ADDRESS, SEC_ASN1_DS},
    1.70 +    { "postalCode",     40, SEC_OID_AVA_POSTAL_CODE,    SEC_ASN1_DS},
    1.71 +    { "postOfficeBox",  40, SEC_OID_AVA_POST_OFFICE_BOX,SEC_ASN1_DS},
    1.72 +    { "houseIdentifier",64, SEC_OID_AVA_HOUSE_IDENTIFIER,SEC_ASN1_DS},
    1.73 +/* end of IANA registered type names */
    1.74 +
    1.75 +/* legacy keywords */
    1.76 +    { "E",             128, SEC_OID_PKCS9_EMAIL_ADDRESS,SEC_ASN1_IA5_STRING},
    1.77 +    { "STREET",        128, SEC_OID_AVA_STREET_ADDRESS, SEC_ASN1_DS},
    1.78 +    { "pseudonym",      64, SEC_OID_AVA_PSEUDONYM,      SEC_ASN1_DS},
    1.79 +
    1.80 +/* values defined by the CAB Forum for EV */
    1.81 +    { "incorporationLocality", 128, SEC_OID_EV_INCORPORATION_LOCALITY,
    1.82 +                                                        SEC_ASN1_DS},
    1.83 +    { "incorporationState",    128, SEC_OID_EV_INCORPORATION_STATE,
    1.84 +                                                        SEC_ASN1_DS},
    1.85 +    { "incorporationCountry",    2, SEC_OID_EV_INCORPORATION_COUNTRY,
    1.86 +                                                    SEC_ASN1_PRINTABLE_STRING},
    1.87 +    { "businessCategory",       64, SEC_OID_BUSINESS_CATEGORY, SEC_ASN1_DS},
    1.88 +
    1.89 +/* values defined in X.520 */
    1.90 +    { "name",           64, SEC_OID_AVA_NAME,           SEC_ASN1_DS},
    1.91 +
    1.92 +    { 0,               256, SEC_OID_UNKNOWN,            0},
    1.93 +};
    1.94 +
    1.95 +/* Table facilitates conversion of ASCII hex to binary. */
    1.96 +static const PRInt16 x2b[256] = {
    1.97 +/* #0x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
    1.98 +/* #1x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
    1.99 +/* #2x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
   1.100 +/* #3x */  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1, 
   1.101 +/* #4x */ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
   1.102 +/* #5x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
   1.103 +/* #6x */ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
   1.104 +/* #7x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
   1.105 +/* #8x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
   1.106 +/* #9x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
   1.107 +/* #ax */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
   1.108 +/* #bx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
   1.109 +/* #cx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
   1.110 +/* #dx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
   1.111 +/* #ex */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
   1.112 +/* #fx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
   1.113 +};
   1.114 +
   1.115 +#define IS_HEX(c) (x2b[(PRUint8)(c)] >= 0)
   1.116 +
   1.117 +#define C_DOUBLE_QUOTE '\042'
   1.118 +
   1.119 +#define C_BACKSLASH '\134'
   1.120 +
   1.121 +#define C_EQUAL '='
   1.122 +
   1.123 +#define OPTIONAL_SPACE(c) \
   1.124 +    (((c) == ' ') || ((c) == '\r') || ((c) == '\n'))
   1.125 +
   1.126 +#define SPECIAL_CHAR(c)						\
   1.127 +    (((c) == ',') || ((c) == '=') || ((c) == C_DOUBLE_QUOTE) ||	\
   1.128 +     ((c) == '\r') || ((c) == '\n') || ((c) == '+') ||		\
   1.129 +     ((c) == '<') || ((c) == '>') || ((c) == '#') ||		\
   1.130 +     ((c) == ';') || ((c) == C_BACKSLASH))
   1.131 +
   1.132 +
   1.133 +#define IS_PRINTABLE(c)						\
   1.134 +    ((((c) >= 'a') && ((c) <= 'z')) ||				\
   1.135 +     (((c) >= 'A') && ((c) <= 'Z')) ||				\
   1.136 +     (((c) >= '0') && ((c) <= '9')) ||				\
   1.137 +     ((c) == ' ') ||						\
   1.138 +     ((c) == '\'') ||						\
   1.139 +     ((c) == '\050') ||				/* ( */		\
   1.140 +     ((c) == '\051') ||				/* ) */		\
   1.141 +     (((c) >= '+') && ((c) <= '/')) ||		/* + , - . / */	\
   1.142 +     ((c) == ':') ||						\
   1.143 +     ((c) == '=') ||						\
   1.144 +     ((c) == '?'))
   1.145 +
   1.146 +/* RFC 2253 says we must escape ",+\"\\<>;=" EXCEPT inside a quoted string.
   1.147 + * Inside a quoted string, we only need to escape " and \
   1.148 + * We choose to quote strings containing any of those special characters,
   1.149 + * so we only need to escape " and \
   1.150 + */
   1.151 +#define NEEDS_ESCAPE(c) \
   1.152 +    (c == C_DOUBLE_QUOTE || c == C_BACKSLASH)
   1.153 +
   1.154 +#define NEEDS_HEX_ESCAPE(c) \
   1.155 +    ((PRUint8)c < 0x20 || c == 0x7f)
   1.156 +
   1.157 +int
   1.158 +cert_AVAOidTagToMaxLen(SECOidTag tag)
   1.159 +{
   1.160 +    const NameToKind *n2k = name2kinds;
   1.161 +
   1.162 +    while (n2k->kind != tag && n2k->kind != SEC_OID_UNKNOWN) {
   1.163 +	++n2k;
   1.164 +    }
   1.165 +    return (n2k->kind != SEC_OID_UNKNOWN) ? n2k->maxLen : -1;
   1.166 +}
   1.167 +
   1.168 +static PRBool
   1.169 +IsPrintable(unsigned char *data, unsigned len)
   1.170 +{
   1.171 +    unsigned char ch, *end;
   1.172 +
   1.173 +    end = data + len;
   1.174 +    while (data < end) {
   1.175 +	ch = *data++;
   1.176 +	if (!IS_PRINTABLE(ch)) {
   1.177 +	    return PR_FALSE;
   1.178 +	}
   1.179 +    }
   1.180 +    return PR_TRUE;
   1.181 +}
   1.182 +
   1.183 +static void
   1.184 +skipSpace(const char **pbp, const char *endptr)
   1.185 +{
   1.186 +    const char *bp = *pbp;
   1.187 +    while (bp < endptr && OPTIONAL_SPACE(*bp)) {
   1.188 +	bp++;
   1.189 +    }
   1.190 +    *pbp = bp;
   1.191 +}
   1.192 +
   1.193 +static SECStatus
   1.194 +scanTag(const char **pbp, const char *endptr, char *tagBuf, int tagBufSize)
   1.195 +{
   1.196 +    const char *bp;
   1.197 +    char *tagBufp;
   1.198 +    int taglen;
   1.199 +
   1.200 +    PORT_Assert(tagBufSize > 0);
   1.201 +    
   1.202 +    /* skip optional leading space */
   1.203 +    skipSpace(pbp, endptr);
   1.204 +    if (*pbp == endptr) {
   1.205 +	/* nothing left */
   1.206 +	return SECFailure;
   1.207 +    }
   1.208 +    
   1.209 +    /* fill tagBuf */
   1.210 +    taglen = 0;
   1.211 +    bp = *pbp;
   1.212 +    tagBufp = tagBuf;
   1.213 +    while (bp < endptr && !OPTIONAL_SPACE(*bp) && (*bp != C_EQUAL)) {
   1.214 +	if (++taglen >= tagBufSize) {
   1.215 +	    *pbp = bp;
   1.216 +	    return SECFailure;
   1.217 +	}
   1.218 +	*tagBufp++ = *bp++;
   1.219 +    }
   1.220 +    /* null-terminate tagBuf -- guaranteed at least one space left */
   1.221 +    *tagBufp++ = 0;
   1.222 +    *pbp = bp;
   1.223 +    
   1.224 +    /* skip trailing spaces till we hit something - should be an equal sign */
   1.225 +    skipSpace(pbp, endptr);
   1.226 +    if (*pbp == endptr) {
   1.227 +	/* nothing left */
   1.228 +	return SECFailure;
   1.229 +    }
   1.230 +    if (**pbp != C_EQUAL) {
   1.231 +	/* should be an equal sign */
   1.232 +	return SECFailure;
   1.233 +    }
   1.234 +    /* skip over the equal sign */
   1.235 +    (*pbp)++;
   1.236 +    
   1.237 +    return SECSuccess;
   1.238 +}
   1.239 +
   1.240 +/* Returns the number of bytes in the value. 0 means failure. */
   1.241 +static int
   1.242 +scanVal(const char **pbp, const char *endptr, char *valBuf, int valBufSize)  
   1.243 +{
   1.244 +    const char *bp;
   1.245 +    char *valBufp;
   1.246 +    int vallen = 0;
   1.247 +    PRBool isQuoted;
   1.248 +    
   1.249 +    PORT_Assert(valBufSize > 0);
   1.250 +    
   1.251 +    /* skip optional leading space */
   1.252 +    skipSpace(pbp, endptr);
   1.253 +    if(*pbp == endptr) {
   1.254 +	/* nothing left */
   1.255 +	return 0;
   1.256 +    }
   1.257 +    
   1.258 +    bp = *pbp;
   1.259 +    
   1.260 +    /* quoted? */
   1.261 +    if (*bp == C_DOUBLE_QUOTE) {
   1.262 +	isQuoted = PR_TRUE;
   1.263 +	/* skip over it */
   1.264 +	bp++;
   1.265 +    } else {
   1.266 +	isQuoted = PR_FALSE;
   1.267 +    }
   1.268 +    
   1.269 +    valBufp = valBuf;
   1.270 +    while (bp < endptr) {
   1.271 +	char c = *bp;
   1.272 +	if (c == C_BACKSLASH) {
   1.273 +	    /* escape character */
   1.274 +	    bp++;
   1.275 +	    if (bp >= endptr) {
   1.276 +		/* escape charater must appear with paired char */
   1.277 +		*pbp = bp;
   1.278 +		return 0;
   1.279 +	    }
   1.280 +	    c = *bp;
   1.281 +	    if (IS_HEX(c) && (endptr - bp) >= 2 && IS_HEX(bp[1])) {
   1.282 +		bp++;
   1.283 +		c = (char)((x2b[(PRUint8)c] << 4) | x2b[(PRUint8)*bp]); 
   1.284 +	    }
   1.285 +	} else if (c == '#' && bp == *pbp) {
   1.286 +	    /* ignore leading #, quotation not required for it. */
   1.287 +	} else if (!isQuoted && SPECIAL_CHAR(c)) {
   1.288 +	    /* unescaped special and not within quoted value */
   1.289 +	    break;
   1.290 +	} else if (c == C_DOUBLE_QUOTE) {
   1.291 +	    /* reached unescaped double quote */
   1.292 +	    break;
   1.293 +	}
   1.294 +	/* append character */
   1.295 +        vallen++;
   1.296 +	if (vallen >= valBufSize) {
   1.297 +	    *pbp = bp;
   1.298 +	    return 0;
   1.299 +	}
   1.300 +	*valBufp++ = c;
   1.301 +	bp++;
   1.302 +    }
   1.303 +    
   1.304 +    /* strip trailing spaces from unquoted values */
   1.305 +    if (!isQuoted) {
   1.306 +	while (valBufp > valBuf) {
   1.307 +	    char c = valBufp[-1];
   1.308 +	    if (! OPTIONAL_SPACE(c))
   1.309 +	        break;
   1.310 +	    --valBufp;
   1.311 +	}
   1.312 +	vallen = valBufp - valBuf;
   1.313 +    }
   1.314 +    
   1.315 +    if (isQuoted) {
   1.316 +	/* insist that we stopped on a double quote */
   1.317 +	if (*bp != C_DOUBLE_QUOTE) {
   1.318 +	    *pbp = bp;
   1.319 +	    return 0;
   1.320 +	}
   1.321 +	/* skip over the quote and skip optional space */
   1.322 +	bp++;
   1.323 +	skipSpace(&bp, endptr);
   1.324 +    }
   1.325 +    
   1.326 +    *pbp = bp;
   1.327 +    
   1.328 +    /* null-terminate valBuf -- guaranteed at least one space left */
   1.329 +    *valBufp = 0;
   1.330 +    
   1.331 +    return vallen;
   1.332 +}
   1.333 +
   1.334 +/* Caller must set error code upon failure */
   1.335 +static SECStatus
   1.336 +hexToBin(PLArenaPool *pool, SECItem * destItem, const char * src, int len)
   1.337 +{
   1.338 +    PRUint8 * dest;
   1.339 +
   1.340 +    destItem->data = NULL; 
   1.341 +    if (len <= 0 || (len & 1)) {
   1.342 +	goto loser;
   1.343 +    }
   1.344 +    len >>= 1;
   1.345 +    if (!SECITEM_AllocItem(pool, destItem, len))
   1.346 +	goto loser;
   1.347 +    dest = destItem->data;
   1.348 +    for (; len > 0; len--, src += 2) {
   1.349 +	PRInt16 bin = (x2b[(PRUint8)src[0]] << 4) | x2b[(PRUint8)src[1]]; 
   1.350 +	if (bin < 0)
   1.351 +	    goto loser;
   1.352 +	*dest++ = (PRUint8)bin;
   1.353 +    }
   1.354 +    return SECSuccess;
   1.355 +loser:
   1.356 +    if (!pool)
   1.357 +    	SECITEM_FreeItem(destItem, PR_FALSE);
   1.358 +    return SECFailure;
   1.359 +}
   1.360 +
   1.361 +/* Parses one AVA, starting at *pbp.  Stops at endptr.
   1.362 + * Advances *pbp past parsed AVA and trailing separator (if present).
   1.363 + * On any error, returns NULL and *pbp is undefined.
   1.364 + * On success, returns CERTAVA allocated from arena, and (*pbp)[-1] was 
   1.365 + * the last character parsed.  *pbp is either equal to endptr or 
   1.366 + * points to first character after separator.
   1.367 + */
   1.368 +static CERTAVA *
   1.369 +ParseRFC1485AVA(PLArenaPool *arena, const char **pbp, const char *endptr)
   1.370 +{
   1.371 +    CERTAVA *a;
   1.372 +    const NameToKind *n2k;
   1.373 +    const char *bp;
   1.374 +    int       vt = -1;
   1.375 +    int       valLen;
   1.376 +    SECOidTag kind  = SEC_OID_UNKNOWN;
   1.377 +    SECStatus rv    = SECFailure;
   1.378 +    SECItem   derOid = { 0, NULL, 0 };
   1.379 +    SECItem   derVal = { 0, NULL, 0};
   1.380 +    char      sep   = 0;
   1.381 +
   1.382 +    char tagBuf[32];
   1.383 +    char valBuf[1024];
   1.384 +
   1.385 +    PORT_Assert(arena);
   1.386 +    if (SECSuccess != scanTag(pbp, endptr, tagBuf, sizeof tagBuf) ||
   1.387 +	!(valLen    = scanVal(pbp, endptr, valBuf, sizeof valBuf))) {
   1.388 +	goto loser;
   1.389 +    }
   1.390 +
   1.391 +    bp = *pbp;
   1.392 +    if (bp < endptr) {
   1.393 +	sep = *bp++; /* skip over separator */
   1.394 +    }
   1.395 +    *pbp = bp;
   1.396 +    /* if we haven't finished, insist that we've stopped on a separator */
   1.397 +    if (sep && sep != ',' && sep != ';' && sep != '+') {
   1.398 +	goto loser;
   1.399 +    }
   1.400 +
   1.401 +    /* is this a dotted decimal OID attribute type ? */
   1.402 +    if (!PL_strncasecmp("oid.", tagBuf, 4)) {
   1.403 +        rv = SEC_StringToOID(arena, &derOid, tagBuf, strlen(tagBuf));
   1.404 +    } else {
   1.405 +	for (n2k = name2kinds; n2k->name; n2k++) {
   1.406 +	    SECOidData *oidrec;
   1.407 +	    if (PORT_Strcasecmp(n2k->name, tagBuf) == 0) {
   1.408 +		kind = n2k->kind;
   1.409 +		vt   = n2k->valueType;
   1.410 +		oidrec = SECOID_FindOIDByTag(kind);
   1.411 +		if (oidrec == NULL)
   1.412 +		    goto loser;
   1.413 +		derOid = oidrec->oid;
   1.414 +		break;
   1.415 +	    }
   1.416 +	}
   1.417 +    }
   1.418 +    if (kind == SEC_OID_UNKNOWN && rv != SECSuccess) 
   1.419 +	goto loser;
   1.420 +
   1.421 +    /* Is this a hex encoding of a DER attribute value ? */
   1.422 +    if ('#' == valBuf[0]) {
   1.423 +    	/* convert attribute value from hex to binary */
   1.424 +	rv = hexToBin(arena, &derVal, valBuf + 1, valLen - 1);
   1.425 +	if (rv)
   1.426 +	    goto loser;
   1.427 +	a = CERT_CreateAVAFromRaw(arena, &derOid, &derVal);
   1.428 +    } else {
   1.429 +	if (kind == SEC_OID_UNKNOWN)
   1.430 +	    goto loser;
   1.431 +	if (kind == SEC_OID_AVA_COUNTRY_NAME && valLen != 2)
   1.432 +	    goto loser;
   1.433 +	if (vt == SEC_ASN1_PRINTABLE_STRING &&
   1.434 +	    !IsPrintable((unsigned char*) valBuf, valLen)) 
   1.435 +	    goto loser;
   1.436 +	if (vt == SEC_ASN1_DS) {
   1.437 +	    /* RFC 4630: choose PrintableString or UTF8String */
   1.438 +	    if (IsPrintable((unsigned char*) valBuf, valLen))
   1.439 +		vt = SEC_ASN1_PRINTABLE_STRING;
   1.440 +	    else 
   1.441 +		vt = SEC_ASN1_UTF8_STRING;
   1.442 +	}
   1.443 +
   1.444 +	derVal.data = (unsigned char*) valBuf;
   1.445 +	derVal.len  = valLen;
   1.446 +	a = CERT_CreateAVAFromSECItem(arena, kind, vt, &derVal);
   1.447 +    }
   1.448 +    return a;
   1.449 +
   1.450 +loser:
   1.451 +    /* matched no kind -- invalid tag */
   1.452 +    PORT_SetError(SEC_ERROR_INVALID_AVA);
   1.453 +    return 0;
   1.454 +}
   1.455 +
   1.456 +static CERTName *
   1.457 +ParseRFC1485Name(const char *buf, int len)
   1.458 +{
   1.459 +    SECStatus rv;
   1.460 +    CERTName *name;
   1.461 +    const char *bp, *e;
   1.462 +    CERTAVA *ava;
   1.463 +    CERTRDN *rdn = NULL;
   1.464 +
   1.465 +    name = CERT_CreateName(NULL);
   1.466 +    if (name == NULL) {
   1.467 +	return NULL;
   1.468 +    }
   1.469 +    
   1.470 +    e = buf + len;
   1.471 +    bp = buf;
   1.472 +    while (bp < e) {
   1.473 +	ava = ParseRFC1485AVA(name->arena, &bp, e);
   1.474 +	if (ava == 0) 
   1.475 +	    goto loser;
   1.476 +	if (!rdn) {
   1.477 +	    rdn = CERT_CreateRDN(name->arena, ava, (CERTAVA *)0);
   1.478 +	    if (rdn == 0) 
   1.479 +		goto loser;
   1.480 +	    rv = CERT_AddRDN(name, rdn);
   1.481 +	} else {
   1.482 +	    rv = CERT_AddAVA(name->arena, rdn, ava);
   1.483 +	}
   1.484 +	if (rv) 
   1.485 +	    goto loser;
   1.486 +	if (bp[-1] != '+')
   1.487 +	    rdn = NULL; /* done with this RDN */
   1.488 +	skipSpace(&bp, e);
   1.489 +    }
   1.490 +
   1.491 +    if (name->rdns[0] == 0) {
   1.492 +	/* empty name -- illegal */
   1.493 +	goto loser;
   1.494 +    }
   1.495 +
   1.496 +    /* Reverse order of RDNS to comply with RFC */
   1.497 +    {
   1.498 +	CERTRDN **firstRdn;
   1.499 +	CERTRDN **lastRdn;
   1.500 +	CERTRDN *tmp;
   1.501 +	
   1.502 +	/* get first one */
   1.503 +	firstRdn = name->rdns;
   1.504 +	
   1.505 +	/* find last one */
   1.506 +	lastRdn = name->rdns;
   1.507 +	while (*lastRdn) lastRdn++;
   1.508 +	lastRdn--;
   1.509 +	
   1.510 +	/* reverse list */
   1.511 +	for ( ; firstRdn < lastRdn; firstRdn++, lastRdn--) {
   1.512 +	    tmp = *firstRdn;
   1.513 +	    *firstRdn = *lastRdn;
   1.514 +	    *lastRdn = tmp;
   1.515 +	}
   1.516 +    }
   1.517 +    
   1.518 +    /* return result */
   1.519 +    return name;
   1.520 +    
   1.521 +  loser:
   1.522 +    CERT_DestroyName(name);
   1.523 +    return NULL;
   1.524 +}
   1.525 +
   1.526 +CERTName *
   1.527 +CERT_AsciiToName(const char *string)
   1.528 +{
   1.529 +    CERTName *name;
   1.530 +    name = ParseRFC1485Name(string, PORT_Strlen(string));
   1.531 +    return name;
   1.532 +}
   1.533 +
   1.534 +/************************************************************************/
   1.535 +
   1.536 +typedef struct stringBufStr {
   1.537 +    char *buffer;
   1.538 +    unsigned offset;
   1.539 +    unsigned size;
   1.540 +} stringBuf;
   1.541 +
   1.542 +#define DEFAULT_BUFFER_SIZE 200
   1.543 +
   1.544 +static SECStatus
   1.545 +AppendStr(stringBuf *bufp, char *str)
   1.546 +{
   1.547 +    char *buf;
   1.548 +    unsigned bufLen, bufSize, len;
   1.549 +    int size = 0;
   1.550 +
   1.551 +    /* Figure out how much to grow buf by (add in the '\0') */
   1.552 +    buf = bufp->buffer;
   1.553 +    bufLen = bufp->offset;
   1.554 +    len = PORT_Strlen(str);
   1.555 +    bufSize = bufLen + len;
   1.556 +    if (!buf) {
   1.557 +	bufSize++;
   1.558 +	size = PR_MAX(DEFAULT_BUFFER_SIZE,bufSize*2);
   1.559 +	buf = (char *) PORT_Alloc(size);
   1.560 +	bufp->size = size;
   1.561 +    } else if (bufp->size < bufSize) {
   1.562 +	size = bufSize*2;
   1.563 +	buf =(char *) PORT_Realloc(buf,size);
   1.564 +	bufp->size = size;
   1.565 +    }
   1.566 +    if (!buf) {
   1.567 +	PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.568 +	return SECFailure;
   1.569 +    }
   1.570 +    bufp->buffer = buf;
   1.571 +    bufp->offset = bufSize;
   1.572 +
   1.573 +    /* Concatenate str onto buf */
   1.574 +    buf = buf + bufLen;
   1.575 +    if (bufLen) buf--;			/* stomp on old '\0' */
   1.576 +    PORT_Memcpy(buf, str, len+1);		/* put in new null */
   1.577 +    return SECSuccess;
   1.578 +}
   1.579 +
   1.580 +typedef enum {
   1.581 +    minimalEscape = 0,		/* only hex escapes, and " and \ */
   1.582 +    minimalEscapeAndQuote,	/* as above, plus quoting        */
   1.583 +    fullEscape                  /* no quoting, full escaping     */
   1.584 +} EQMode;
   1.585 +
   1.586 +/* Some characters must be escaped as a hex string, e.g. c -> \nn .
   1.587 + * Others must be escaped by preceding with a '\', e.g. c -> \c , but
   1.588 + * there are certain "special characters" that may be handled by either
   1.589 + * escaping them, or by enclosing the entire attribute value in quotes.
   1.590 + * A NULL value for pEQMode implies selecting minimalEscape mode.
   1.591 + * Some callers will do quoting when needed, others will not.
   1.592 + * If a caller selects minimalEscapeAndQuote, and the string does not
   1.593 + * need quoting, then this function changes it to minimalEscape.
   1.594 + */
   1.595 +static int
   1.596 +cert_RFC1485_GetRequiredLen(const char *src, int srclen, EQMode *pEQMode)
   1.597 +{
   1.598 +    int i, reqLen=0;
   1.599 +    EQMode mode = pEQMode ? *pEQMode : minimalEscape;
   1.600 +    PRBool needsQuoting = PR_FALSE;
   1.601 +    char lastC = 0;
   1.602 +
   1.603 +    /* need to make an initial pass to determine if quoting is needed */
   1.604 +    for (i = 0; i < srclen; i++) {
   1.605 +	char c = src[i];
   1.606 +	reqLen++;
   1.607 +	if (NEEDS_HEX_ESCAPE(c)) {      /* c -> \xx  */
   1.608 +	    reqLen += 2;
   1.609 +	} else if (NEEDS_ESCAPE(c)) {   /* c -> \c   */
   1.610 +	    reqLen++;
   1.611 +	} else if (SPECIAL_CHAR(c)) {
   1.612 +	    if (mode == minimalEscapeAndQuote) /* quoting is allowed */
   1.613 +		needsQuoting = PR_TRUE; /* entirety will need quoting */
   1.614 +	    else if (mode == fullEscape)
   1.615 +	    	reqLen++;               /* MAY escape this character */
   1.616 +	} else if (OPTIONAL_SPACE(c) && OPTIONAL_SPACE(lastC)) {
   1.617 +	    if (mode == minimalEscapeAndQuote) /* quoting is allowed */
   1.618 +		needsQuoting = PR_TRUE; /* entirety will need quoting */
   1.619 +	}
   1.620 +	lastC = c;
   1.621 +    }
   1.622 +    /* if it begins or ends in optional space it needs quoting */
   1.623 +    if (!needsQuoting && srclen > 0 && mode == minimalEscapeAndQuote && 
   1.624 +	(OPTIONAL_SPACE(src[srclen-1]) || OPTIONAL_SPACE(src[0]))) {
   1.625 +	needsQuoting = PR_TRUE;
   1.626 +    }
   1.627 +
   1.628 +    if (needsQuoting) 
   1.629 +    	reqLen += 2;
   1.630 +    if (pEQMode && mode == minimalEscapeAndQuote && !needsQuoting)
   1.631 +    	*pEQMode = minimalEscape;
   1.632 +    return reqLen;
   1.633 +}
   1.634 +
   1.635 +static const char hexChars[16] = { "0123456789abcdef" };
   1.636 +
   1.637 +static SECStatus
   1.638 +escapeAndQuote(char *dst, int dstlen, char *src, int srclen, EQMode *pEQMode)
   1.639 +{
   1.640 +    int i, reqLen=0;
   1.641 +    EQMode mode = pEQMode ? *pEQMode : minimalEscape;
   1.642 +
   1.643 +    /* space for terminal null */
   1.644 +    reqLen = cert_RFC1485_GetRequiredLen(src, srclen, &mode) + 1;
   1.645 +    if (reqLen > dstlen) {
   1.646 +	PORT_SetError(SEC_ERROR_OUTPUT_LEN);
   1.647 +	return SECFailure;
   1.648 +    }
   1.649 +
   1.650 +    if (mode == minimalEscapeAndQuote)
   1.651 +        *dst++ = C_DOUBLE_QUOTE;
   1.652 +    for (i = 0; i < srclen; i++) {
   1.653 +	char c = src[i];
   1.654 +	if (NEEDS_HEX_ESCAPE(c)) {
   1.655 +	    *dst++ = C_BACKSLASH;
   1.656 +	    *dst++ = hexChars[ (c >> 4) & 0x0f ];
   1.657 +	    *dst++ = hexChars[  c       & 0x0f ];
   1.658 +	} else {
   1.659 +	    if (NEEDS_ESCAPE(c) || (SPECIAL_CHAR(c) && mode == fullEscape)) {
   1.660 +		*dst++ = C_BACKSLASH;
   1.661 +	    }
   1.662 +	    *dst++ = c;
   1.663 +	}
   1.664 +    }
   1.665 +    if (mode == minimalEscapeAndQuote)
   1.666 +    	*dst++ = C_DOUBLE_QUOTE;
   1.667 +    *dst++ = 0;
   1.668 +    if (pEQMode)
   1.669 +    	*pEQMode = mode;
   1.670 +    return SECSuccess;
   1.671 +}
   1.672 +
   1.673 +SECStatus
   1.674 +CERT_RFC1485_EscapeAndQuote(char *dst, int dstlen, char *src, int srclen)
   1.675 +{
   1.676 +    EQMode mode = minimalEscapeAndQuote;
   1.677 +    return escapeAndQuote(dst, dstlen, src, srclen, &mode);
   1.678 +}
   1.679 +
   1.680 +
   1.681 +/* convert an OID to dotted-decimal representation */
   1.682 +/* Returns a string that must be freed with PR_smprintf_free(), */
   1.683 +char *
   1.684 +CERT_GetOidString(const SECItem *oid)
   1.685 +{
   1.686 +    PRUint8 *stop;   /* points to first byte after OID string */
   1.687 +    PRUint8 *first;  /* byte of an OID component integer      */
   1.688 +    PRUint8 *last;   /* byte of an OID component integer      */
   1.689 +    char *rvString   = NULL;
   1.690 +    char *prefix     = NULL;
   1.691 +
   1.692 +#define MAX_OID_LEN 1024 /* bytes */
   1.693 +
   1.694 +    if (oid->len > MAX_OID_LEN) {
   1.695 +    	PORT_SetError(SEC_ERROR_INPUT_LEN);
   1.696 +	return NULL;
   1.697 +    }
   1.698 +
   1.699 +    /* first will point to the next sequence of bytes to decode */
   1.700 +    first = (PRUint8 *)oid->data;
   1.701 +    /* stop points to one past the legitimate data */
   1.702 +    stop = &first[ oid->len ];
   1.703 +
   1.704 +    /*
   1.705 +     * Check for our pseudo-encoded single-digit OIDs
   1.706 +     */
   1.707 +    if ((*first == 0x80) && (2 == oid->len)) {
   1.708 +	/* Funky encoding.  The second byte is the number */
   1.709 +	rvString = PR_smprintf("%lu", (PRUint32)first[1]);
   1.710 +	if (!rvString) {
   1.711 +	    PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.712 +	}
   1.713 +	return rvString;
   1.714 +    }
   1.715 +
   1.716 +    for (; first < stop; first = last + 1) {
   1.717 +    	unsigned int bytesBeforeLast;
   1.718 +    
   1.719 +	for (last = first; last < stop; last++) {
   1.720 +	    if (0 == (*last & 0x80)) {
   1.721 +		break;
   1.722 +	    }
   1.723 +	}
   1.724 +	bytesBeforeLast = (unsigned int)(last - first);
   1.725 +	if (bytesBeforeLast <= 3U) {        /* 0-28 bit number */
   1.726 +	    PRUint32 n = 0;
   1.727 +	    PRUint32 c;
   1.728 +
   1.729 +#define CGET(i, m) \
   1.730 +		c  = last[-i] & m; \
   1.731 +		n |= c << (7 * i)
   1.732 +
   1.733 +#define CASE(i, m) \
   1.734 +	    case i:                      \
   1.735 +		CGET(i, m);              \
   1.736 +		if (!n) goto unsupported \
   1.737 +		/* fall-through */
   1.738 +
   1.739 +	    switch (bytesBeforeLast) {
   1.740 +	    CASE(3, 0x7f);
   1.741 +	    CASE(2, 0x7f);
   1.742 +	    CASE(1, 0x7f);
   1.743 +	    case 0: n |= last[0] & 0x7f;
   1.744 +		break;
   1.745 +	    }
   1.746 +	    if (last[0] & 0x80)
   1.747 +	    	goto unsupported;
   1.748 +      
   1.749 +	    if (!rvString) {
   1.750 +		/* This is the first number.. decompose it */
   1.751 +		PRUint32 one = PR_MIN(n/40, 2); /* never > 2 */
   1.752 +		PRUint32 two = n - (one * 40);
   1.753 +        
   1.754 +		rvString = PR_smprintf("OID.%lu.%lu", one, two);
   1.755 +	    } else {
   1.756 +		prefix = rvString;
   1.757 +		rvString = PR_smprintf("%s.%lu", prefix, n);
   1.758 +	    }
   1.759 +	} else if (bytesBeforeLast <= 9U) { /* 29-64 bit number */
   1.760 +	    PRUint64 n = 0;
   1.761 +	    PRUint64 c;
   1.762 +
   1.763 +	    switch (bytesBeforeLast) {
   1.764 +	    CASE(9, 0x01);
   1.765 +	    CASE(8, 0x7f);
   1.766 +	    CASE(7, 0x7f);
   1.767 +	    CASE(6, 0x7f);
   1.768 +	    CASE(5, 0x7f);
   1.769 +	    CASE(4, 0x7f);
   1.770 +	    CGET(3, 0x7f);
   1.771 +	    CGET(2, 0x7f);
   1.772 +	    CGET(1, 0x7f);
   1.773 +	    CGET(0, 0x7f);
   1.774 +		break;
   1.775 +	    }
   1.776 +	    if (last[0] & 0x80)
   1.777 +	    	goto unsupported;
   1.778 +      
   1.779 +	    if (!rvString) {
   1.780 +		/* This is the first number.. decompose it */
   1.781 +		PRUint64 one = PR_MIN(n/40, 2); /* never > 2 */
   1.782 +		PRUint64 two = n - (one * 40);
   1.783 +        
   1.784 +		rvString = PR_smprintf("OID.%llu.%llu", one, two);
   1.785 +	    } else {
   1.786 +		prefix = rvString;
   1.787 +		rvString = PR_smprintf("%s.%llu", prefix, n);
   1.788 +	    }
   1.789 +	} else {
   1.790 +	    /* More than a 64-bit number, or not minimal encoding. */
   1.791 +unsupported:
   1.792 +	    if (!rvString)
   1.793 +		rvString = PR_smprintf("OID.UNSUPPORTED");
   1.794 +	    else {
   1.795 +		prefix = rvString;
   1.796 +		rvString = PR_smprintf("%s.UNSUPPORTED", prefix);
   1.797 +	    }
   1.798 +	}
   1.799 +
   1.800 +	if (prefix) {
   1.801 +	    PR_smprintf_free(prefix);
   1.802 +	    prefix = NULL;
   1.803 +	}
   1.804 +	if (!rvString) {
   1.805 +	    PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.806 +	    break;
   1.807 +	}
   1.808 +    }
   1.809 +    return rvString;
   1.810 +}
   1.811 +
   1.812 +/* convert DER-encoded hex to a string */
   1.813 +static SECItem *
   1.814 +get_hex_string(SECItem *data)
   1.815 +{
   1.816 +    SECItem *rv;
   1.817 +    unsigned int i, j;
   1.818 +    static const char hex[] = { "0123456789ABCDEF" };
   1.819 +
   1.820 +    /* '#' + 2 chars per octet + terminator */
   1.821 +    rv = SECITEM_AllocItem(NULL, NULL, data->len*2 + 2);
   1.822 +    if (!rv) {
   1.823 +	return NULL;
   1.824 +    }
   1.825 +    rv->data[0] = '#';
   1.826 +    rv->len = 1 + 2 * data->len;
   1.827 +    for (i=0; i<data->len; i++) {
   1.828 +	j = data->data[i];
   1.829 +	rv->data[2*i+1] = hex[j >> 4];
   1.830 +	rv->data[2*i+2] = hex[j & 15];
   1.831 +    }
   1.832 +    rv->data[rv->len] = 0;
   1.833 +    return rv;
   1.834 +}
   1.835 +
   1.836 +/* For compliance with RFC 2253, RFC 3280 and RFC 4630, we choose to 
   1.837 + * use the NAME=STRING form, rather than the OID.N.N=#hexXXXX form, 
   1.838 + * when both of these conditions are met:
   1.839 + *  1) The attribute name OID (kind) has a known name string that is 
   1.840 + *     defined in one of those RFCs, or in RFCs that they cite, AND
   1.841 + *  2) The attribute's value encoding is RFC compliant for the kind
   1.842 + *     (e.g., the value's encoding tag is correct for the kind, and
   1.843 + *     the value's length is in the range allowed for the kind, and
   1.844 + *     the value's contents are appropriate for the encoding tag).
   1.845 + *  Otherwise, we use the OID.N.N=#hexXXXX form.
   1.846 + *
   1.847 + *  If the caller prefers maximum human readability to RFC compliance,
   1.848 + *  then 
   1.849 + *  - We print the kind in NAME= string form if we know the name
   1.850 + *    string for the attribute type OID, regardless of whether the 
   1.851 + *    value is correctly encoded or not. else we use the OID.N.N= form.
   1.852 + *  - We use the non-hex STRING form for the attribute value if the
   1.853 + *    value can be represented in such a form.  Otherwise, we use 
   1.854 + *    the hex string form.
   1.855 + *  This implies that, for maximum human readability, in addition to 
   1.856 + *  the two forms allowed by the RFC, we allow two other forms of output:
   1.857 + *  - the OID.N.N=STRING form, and 
   1.858 + *  - the NAME=#hexXXXX form
   1.859 + *  When the caller prefers maximum human readability, we do not allow
   1.860 + *  the value of any attribute to exceed the length allowed by the RFC.
   1.861 + *  If the attribute value exceeds the allowed length, we truncate it to 
   1.862 + *  the allowed length and append "...".
   1.863 + *  Also in this case, we arbitrarily impose a limit on the length of the 
   1.864 + *  entire AVA encoding, regardless of the form, of 384 bytes per AVA.
   1.865 + *  This limit includes the trailing NULL character.  If the encoded 
   1.866 + *  AVA length exceeds that limit, this function reports failure to encode
   1.867 + *  the AVA.
   1.868 + *
   1.869 + *  An ASCII representation of an AVA is said to be "invertible" if 
   1.870 + *  conversion back to DER reproduces the original DER encoding exactly.
   1.871 + *  The RFC 2253 rules do not ensure that all ASCII AVAs derived according
   1.872 + *  to its rules are invertible. That is because the RFCs allow some 
   1.873 + *  attribute values to be encoded in any of a number of encodings,
   1.874 + *  and the encoding type information is lost in the non-hex STRING form.
   1.875 + *  This is particularly true of attributes of type DirectoryString.
   1.876 + *  The encoding type information is always preserved in the hex string 
   1.877 + *  form, because the hex includes the entire DER encoding of the value.
   1.878 + *
   1.879 + *  So, when the caller perfers maximum invertibility, we apply the 
   1.880 + *  RFC compliance rules stated above, and add a third required 
   1.881 + *  condition on the use of the NAME=STRING form.  
   1.882 + *   3) The attribute's kind is not is allowed to be encoded in any of 
   1.883 + *      several different encodings, such as DirectoryStrings.
   1.884 + *
   1.885 + * The chief difference between CERT_N2A_STRICT and CERT_N2A_INVERTIBLE
   1.886 + * is that the latter forces DirectoryStrings to be hex encoded.
   1.887 + *
   1.888 + * As a simplification, we assume the value is correctly encoded for 
   1.889 + * its encoding type.  That is, we do not test that all the characters
   1.890 + * in a string encoded type are allowed by that type.  We assume it.
   1.891 + */
   1.892 +static SECStatus
   1.893 +AppendAVA(stringBuf *bufp, CERTAVA *ava, CertStrictnessLevel strict)
   1.894 +{
   1.895 +#define TMPBUF_LEN 2048
   1.896 +    const NameToKind *pn2k   = name2kinds;
   1.897 +    SECItem     *avaValue    = NULL;
   1.898 +    char        *unknownTag  = NULL;
   1.899 +    char        *encodedAVA  = NULL;
   1.900 +    PRBool       useHex      = PR_FALSE;  /* use =#hexXXXX form */
   1.901 +    PRBool       truncateName  = PR_FALSE;
   1.902 +    PRBool       truncateValue = PR_FALSE;
   1.903 +    SECOidTag    endKind;
   1.904 +    SECStatus    rv;
   1.905 +    unsigned int len;
   1.906 +    unsigned int nameLen, valueLen;
   1.907 +    unsigned int maxName, maxValue;
   1.908 +    EQMode       mode        = minimalEscapeAndQuote;
   1.909 +    NameToKind   n2k         = { NULL, 32767, SEC_OID_UNKNOWN, SEC_ASN1_DS };
   1.910 +    char         tmpBuf[TMPBUF_LEN];
   1.911 +
   1.912 +#define tagName  n2k.name    /* non-NULL means use NAME= form */
   1.913 +#define maxBytes n2k.maxLen
   1.914 +#define tag      n2k.kind
   1.915 +#define vt       n2k.valueType
   1.916 +
   1.917 +    /* READABLE mode recognizes more names from the name2kinds table
   1.918 +     * than do STRICT or INVERTIBLE modes.  This assignment chooses the
   1.919 +     * point in the table where the attribute type name scanning stops.
   1.920 +     */
   1.921 +    endKind = (strict == CERT_N2A_READABLE) ? SEC_OID_UNKNOWN
   1.922 +                                            : SEC_OID_AVA_POSTAL_ADDRESS;
   1.923 +    tag = CERT_GetAVATag(ava);
   1.924 +    while (pn2k->kind != tag && pn2k->kind != endKind) {
   1.925 +        ++pn2k;
   1.926 +    }
   1.927 +
   1.928 +    if (pn2k->kind != endKind ) {
   1.929 +        n2k = *pn2k;
   1.930 +    } else if (strict != CERT_N2A_READABLE) {
   1.931 +        useHex = PR_TRUE;
   1.932 +    }
   1.933 +    /* For invertable form, force Directory Strings to use hex form. */
   1.934 +    if (strict == CERT_N2A_INVERTIBLE && vt == SEC_ASN1_DS) {
   1.935 +	tagName = NULL;      /* must use OID.N form */
   1.936 +	useHex = PR_TRUE;    /* must use hex string */
   1.937 +    }
   1.938 +    if (!useHex) {
   1.939 +	avaValue = CERT_DecodeAVAValue(&ava->value);
   1.940 +	if (!avaValue) {
   1.941 +	    useHex = PR_TRUE;
   1.942 +	    if (strict != CERT_N2A_READABLE) {
   1.943 +		tagName = NULL;  /* must use OID.N form */
   1.944 +	    }
   1.945 +	}
   1.946 +    }
   1.947 +    if (!tagName) {
   1.948 +	/* handle unknown attribute types per RFC 2253 */
   1.949 +	tagName = unknownTag = CERT_GetOidString(&ava->type);
   1.950 +	if (!tagName) {
   1.951 +	    if (avaValue)
   1.952 +		SECITEM_FreeItem(avaValue, PR_TRUE);
   1.953 +	    return SECFailure;
   1.954 +	}
   1.955 +    }
   1.956 +    if (useHex) {
   1.957 +	avaValue = get_hex_string(&ava->value);
   1.958 +	if (!avaValue) {
   1.959 +	    if (unknownTag) 
   1.960 +	    	PR_smprintf_free(unknownTag);
   1.961 +	    return SECFailure;
   1.962 +	}
   1.963 +    }
   1.964 +
   1.965 +    nameLen  = strlen(tagName);
   1.966 +    valueLen = (useHex ? avaValue->len : 
   1.967 +		cert_RFC1485_GetRequiredLen((char *)avaValue->data, avaValue->len, 
   1.968 +					    &mode));
   1.969 +    len = nameLen + valueLen + 2; /* Add 2 for '=' and trailing NUL */
   1.970 +
   1.971 +    maxName  = nameLen;
   1.972 +    maxValue = valueLen;
   1.973 +    if (len <= sizeof(tmpBuf)) {
   1.974 +    	encodedAVA = tmpBuf;
   1.975 +    } else if (strict != CERT_N2A_READABLE) {
   1.976 +	encodedAVA = PORT_Alloc(len);
   1.977 +	if (!encodedAVA) {
   1.978 +	    SECITEM_FreeItem(avaValue, PR_TRUE);
   1.979 +	    if (unknownTag) 
   1.980 +		PR_smprintf_free(unknownTag);
   1.981 +	    return SECFailure;
   1.982 +	}
   1.983 +    } else {
   1.984 +	/* Must make output fit in tmpbuf */
   1.985 +	unsigned int fair = (sizeof tmpBuf)/2 - 1; /* for = and \0 */
   1.986 +
   1.987 +	if (nameLen < fair) {
   1.988 +	    /* just truncate the value */
   1.989 +	    maxValue = (sizeof tmpBuf) - (nameLen + 6); /* for "=...\0",
   1.990 +                                                           and possibly '"' */
   1.991 +	} else if (valueLen < fair) {
   1.992 +	    /* just truncate the name */
   1.993 +	    maxName  = (sizeof tmpBuf) - (valueLen + 5); /* for "=...\0" */
   1.994 +	} else {
   1.995 +	    /* truncate both */
   1.996 +	    maxName = maxValue = fair - 3;  /* for "..." */
   1.997 +	}
   1.998 +	if (nameLen > maxName) {
   1.999 +	    PORT_Assert(unknownTag && unknownTag == tagName);
  1.1000 +	    truncateName = PR_TRUE;
  1.1001 +	    nameLen = maxName;
  1.1002 +	}
  1.1003 +    	encodedAVA = tmpBuf;
  1.1004 +    }
  1.1005 +
  1.1006 +    memcpy(encodedAVA, tagName, nameLen);
  1.1007 +    if (truncateName) {
  1.1008 +	/* If tag name is too long, we know it is an OID form that was 
  1.1009 +	 * allocated from the heap, so we can modify it in place 
  1.1010 +	 */
  1.1011 +	encodedAVA[nameLen-1] = '.';
  1.1012 +	encodedAVA[nameLen-2] = '.';
  1.1013 +	encodedAVA[nameLen-3] = '.';
  1.1014 +    }
  1.1015 +    encodedAVA[nameLen++] = '=';
  1.1016 +    if (unknownTag) 
  1.1017 +    	PR_smprintf_free(unknownTag);
  1.1018 +
  1.1019 +    if (strict == CERT_N2A_READABLE && maxValue > maxBytes)
  1.1020 +	maxValue = maxBytes;
  1.1021 +    if (valueLen > maxValue) {
  1.1022 +    	valueLen = maxValue;
  1.1023 +	truncateValue = PR_TRUE;
  1.1024 +    }
  1.1025 +    /* escape and quote as necessary - don't quote hex strings */
  1.1026 +    if (useHex) {
  1.1027 +	char * end = encodedAVA + nameLen + valueLen;
  1.1028 +	memcpy(encodedAVA + nameLen, (char *)avaValue->data, valueLen);
  1.1029 +	end[0] = '\0';
  1.1030 +	if (truncateValue) {
  1.1031 +	    end[-1] = '.';
  1.1032 +	    end[-2] = '.';
  1.1033 +	    end[-3] = '.';
  1.1034 +	}
  1.1035 +	rv = SECSuccess;
  1.1036 +    } else if (!truncateValue) {
  1.1037 +	rv = escapeAndQuote(encodedAVA + nameLen, len - nameLen, 
  1.1038 +			    (char *)avaValue->data, avaValue->len, &mode);
  1.1039 +    } else {
  1.1040 +	/* must truncate the escaped and quoted value */
  1.1041 +	char bigTmpBuf[TMPBUF_LEN * 3 + 3];
  1.1042 +	PORT_Assert(valueLen < sizeof tmpBuf);
  1.1043 +	rv = escapeAndQuote(bigTmpBuf, sizeof bigTmpBuf,
  1.1044 +			    (char *)avaValue->data,
  1.1045 +			    PR_MIN(avaValue->len, valueLen), &mode);
  1.1046 +
  1.1047 +	bigTmpBuf[valueLen--] = '\0'; /* hard stop here */
  1.1048 +	/* See if we're in the middle of a multi-byte UTF8 character */
  1.1049 +	while (((bigTmpBuf[valueLen] & 0xc0) == 0x80) && valueLen > 0) {
  1.1050 +	    bigTmpBuf[valueLen--] = '\0';
  1.1051 +	}
  1.1052 +	/* add ellipsis to signify truncation. */
  1.1053 +	bigTmpBuf[++valueLen] = '.';
  1.1054 +	bigTmpBuf[++valueLen] = '.';
  1.1055 +	bigTmpBuf[++valueLen] = '.';
  1.1056 +	if (bigTmpBuf[0] == '"')
  1.1057 +	    bigTmpBuf[++valueLen] = '"';
  1.1058 +	bigTmpBuf[++valueLen] = '\0';
  1.1059 +	PORT_Assert(nameLen + valueLen <= (sizeof tmpBuf) - 1);
  1.1060 +	memcpy(encodedAVA + nameLen, bigTmpBuf, valueLen+1);
  1.1061 +    }
  1.1062 +
  1.1063 +    SECITEM_FreeItem(avaValue, PR_TRUE);
  1.1064 +    if (rv == SECSuccess)
  1.1065 +	rv = AppendStr(bufp, encodedAVA);
  1.1066 +    if (encodedAVA != tmpBuf)
  1.1067 +    	PORT_Free(encodedAVA);
  1.1068 +    return rv;
  1.1069 +}
  1.1070 +
  1.1071 +#undef tagName
  1.1072 +#undef maxBytes
  1.1073 +#undef tag
  1.1074 +#undef vt
  1.1075 +
  1.1076 +char *
  1.1077 +CERT_NameToAsciiInvertible(CERTName *name, CertStrictnessLevel strict)
  1.1078 +{
  1.1079 +    CERTRDN** rdns;
  1.1080 +    CERTRDN** lastRdn;
  1.1081 +    CERTRDN** rdn;
  1.1082 +    PRBool first = PR_TRUE;
  1.1083 +    stringBuf strBuf = { NULL, 0, 0 };
  1.1084 +    
  1.1085 +    rdns = name->rdns;
  1.1086 +    if (rdns == NULL) {
  1.1087 +	return NULL;
  1.1088 +    }
  1.1089 +    
  1.1090 +    /* find last RDN */
  1.1091 +    lastRdn = rdns;
  1.1092 +    while (*lastRdn) lastRdn++;
  1.1093 +    lastRdn--;
  1.1094 +    
  1.1095 +    /*
  1.1096 +     * Loop over name contents in _reverse_ RDN order appending to string
  1.1097 +     */
  1.1098 +    for (rdn = lastRdn; rdn >= rdns; rdn--) {
  1.1099 +	CERTAVA** avas = (*rdn)->avas;
  1.1100 +	CERTAVA* ava;
  1.1101 +	PRBool newRDN = PR_TRUE;
  1.1102 +
  1.1103 +	/* 
  1.1104 +	 * XXX Do we need to traverse the AVAs in reverse order, too?
  1.1105 +	 */
  1.1106 +	while (avas && (ava = *avas++) != NULL) {
  1.1107 +	    SECStatus rv;
  1.1108 +	    /* Put in comma or plus separator */
  1.1109 +	    if (!first) {
  1.1110 +		/* Use of spaces is deprecated in RFC 2253. */
  1.1111 +		rv = AppendStr(&strBuf, newRDN ? "," : "+");
  1.1112 +		if (rv) goto loser;
  1.1113 +	    } else {
  1.1114 +		first = PR_FALSE;
  1.1115 +	    }
  1.1116 +	    
  1.1117 +	    /* Add in tag type plus value into strBuf */
  1.1118 +	    rv = AppendAVA(&strBuf, ava, strict);
  1.1119 +	    if (rv) goto loser;
  1.1120 +	    newRDN = PR_FALSE;
  1.1121 +	}
  1.1122 +    }
  1.1123 +    return strBuf.buffer;
  1.1124 +loser:
  1.1125 +    if (strBuf.buffer) {
  1.1126 +	PORT_Free(strBuf.buffer);
  1.1127 +    }
  1.1128 +    return NULL;
  1.1129 +}
  1.1130 +
  1.1131 +char *
  1.1132 +CERT_NameToAscii(CERTName *name)
  1.1133 +{
  1.1134 +    return CERT_NameToAsciiInvertible(name, CERT_N2A_READABLE);
  1.1135 +}
  1.1136 +
  1.1137 +/*
  1.1138 + * Return the string representation of a DER encoded distinguished name
  1.1139 + * "dername" - The DER encoded name to convert
  1.1140 + */
  1.1141 +char *
  1.1142 +CERT_DerNameToAscii(SECItem *dername)
  1.1143 +{
  1.1144 +    int rv;
  1.1145 +    PLArenaPool *arena = NULL;
  1.1146 +    CERTName name;
  1.1147 +    char *retstr = NULL;
  1.1148 +    
  1.1149 +    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.1150 +    
  1.1151 +    if ( arena == NULL) {
  1.1152 +	goto loser;
  1.1153 +    }
  1.1154 +    
  1.1155 +    rv = SEC_QuickDERDecodeItem(arena, &name, CERT_NameTemplate, dername);
  1.1156 +    
  1.1157 +    if ( rv != SECSuccess ) {
  1.1158 +	goto loser;
  1.1159 +    }
  1.1160 +
  1.1161 +    retstr = CERT_NameToAscii(&name);
  1.1162 +
  1.1163 +loser:
  1.1164 +    if ( arena != NULL ) {
  1.1165 +	PORT_FreeArena(arena, PR_FALSE);
  1.1166 +    }
  1.1167 +    
  1.1168 +    return(retstr);
  1.1169 +}
  1.1170 +
  1.1171 +static char *
  1.1172 +avaToString(PLArenaPool *arena, CERTAVA *ava)
  1.1173 +{
  1.1174 +    char *    buf       = NULL;
  1.1175 +    SECItem*  avaValue;
  1.1176 +    int       valueLen;
  1.1177 +
  1.1178 +    avaValue = CERT_DecodeAVAValue(&ava->value);
  1.1179 +    if(!avaValue) {
  1.1180 +	return buf;
  1.1181 +    }
  1.1182 +    valueLen = cert_RFC1485_GetRequiredLen((char *)avaValue->data,
  1.1183 +                                           avaValue->len, NULL) + 1;
  1.1184 +    if (arena) {
  1.1185 +	buf = (char *)PORT_ArenaZAlloc(arena, valueLen);
  1.1186 +    } else {
  1.1187 +	buf = (char *)PORT_ZAlloc(valueLen);
  1.1188 +    }
  1.1189 +    if (buf) {
  1.1190 +	SECStatus rv = escapeAndQuote(buf, valueLen, (char *)avaValue->data, 
  1.1191 +	                              avaValue->len, NULL);
  1.1192 +	if (rv != SECSuccess) {
  1.1193 +	    if (!arena)
  1.1194 +		PORT_Free(buf);
  1.1195 +	    buf = NULL;
  1.1196 +	}
  1.1197 +    }
  1.1198 +    SECITEM_FreeItem(avaValue, PR_TRUE);
  1.1199 +    return buf;
  1.1200 +}
  1.1201 +
  1.1202 +/* RDNs are sorted from most general to most specific.
  1.1203 + * This code returns the FIRST one found, the most general one found.
  1.1204 + */
  1.1205 +static char *
  1.1206 +CERT_GetNameElement(PLArenaPool *arena, const CERTName *name, int wantedTag)
  1.1207 +{
  1.1208 +    CERTRDN** rdns = name->rdns;
  1.1209 +    CERTRDN*  rdn;
  1.1210 +    CERTAVA*  ava  = NULL;
  1.1211 +
  1.1212 +    while (rdns && (rdn = *rdns++) != 0) {
  1.1213 +	CERTAVA** avas = rdn->avas;
  1.1214 +	while (avas && (ava = *avas++) != 0) {
  1.1215 +	    int tag = CERT_GetAVATag(ava);
  1.1216 +	    if ( tag == wantedTag ) {
  1.1217 +		avas = NULL;
  1.1218 +		rdns = NULL; /* break out of all loops */
  1.1219 +	    }
  1.1220 +	}
  1.1221 +    }
  1.1222 +    return ava ? avaToString(arena, ava) : NULL;
  1.1223 +}
  1.1224 +
  1.1225 +/* RDNs are sorted from most general to most specific.
  1.1226 + * This code returns the LAST one found, the most specific one found.
  1.1227 + * This is particularly appropriate for Common Name.  See RFC 2818.
  1.1228 + */
  1.1229 +static char *
  1.1230 +CERT_GetLastNameElement(PLArenaPool *arena, const CERTName *name, int wantedTag)
  1.1231 +{
  1.1232 +    CERTRDN** rdns    = name->rdns;
  1.1233 +    CERTRDN*  rdn;
  1.1234 +    CERTAVA*  lastAva = NULL;
  1.1235 +    
  1.1236 +    while (rdns && (rdn = *rdns++) != 0) {
  1.1237 +	CERTAVA** avas = rdn->avas;
  1.1238 +	CERTAVA*  ava;
  1.1239 +	while (avas && (ava = *avas++) != 0) {
  1.1240 +	    int tag = CERT_GetAVATag(ava);
  1.1241 +	    if ( tag == wantedTag ) {
  1.1242 +		lastAva = ava;
  1.1243 +	    }
  1.1244 +	}
  1.1245 +    }
  1.1246 +    return lastAva ? avaToString(arena, lastAva) : NULL;
  1.1247 +}
  1.1248 +
  1.1249 +char *
  1.1250 +CERT_GetCertificateEmailAddress(CERTCertificate *cert)
  1.1251 +{
  1.1252 +    char *rawEmailAddr = NULL;
  1.1253 +    SECItem subAltName;
  1.1254 +    SECStatus rv;
  1.1255 +    CERTGeneralName *nameList = NULL;
  1.1256 +    CERTGeneralName *current;
  1.1257 +    PLArenaPool *arena = NULL;
  1.1258 +    int i;
  1.1259 +    
  1.1260 +    subAltName.data = NULL;
  1.1261 +
  1.1262 +    rawEmailAddr = CERT_GetNameElement(cert->arena, &(cert->subject),
  1.1263 +						 SEC_OID_PKCS9_EMAIL_ADDRESS);
  1.1264 +    if ( rawEmailAddr == NULL ) {
  1.1265 +	rawEmailAddr = CERT_GetNameElement(cert->arena, &(cert->subject), 
  1.1266 +							SEC_OID_RFC1274_MAIL);
  1.1267 +    }
  1.1268 +    if ( rawEmailAddr == NULL) {
  1.1269 +
  1.1270 +	rv = CERT_FindCertExtension(cert,  SEC_OID_X509_SUBJECT_ALT_NAME, 
  1.1271 +								&subAltName);
  1.1272 +	if (rv != SECSuccess) {
  1.1273 +	    goto finish;
  1.1274 +	}
  1.1275 +	arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.1276 +	if (!arena) {
  1.1277 +	    goto finish;
  1.1278 +	}
  1.1279 +	nameList = current = CERT_DecodeAltNameExtension(arena, &subAltName);
  1.1280 +	if (!nameList ) {
  1.1281 +	    goto finish;
  1.1282 +	}
  1.1283 +	if (nameList != NULL) {
  1.1284 +	    do {
  1.1285 +		if (current->type == certDirectoryName) {
  1.1286 +		    rawEmailAddr = CERT_GetNameElement(cert->arena,
  1.1287 +			&(current->name.directoryName), 
  1.1288 +					       SEC_OID_PKCS9_EMAIL_ADDRESS);
  1.1289 +		    if ( rawEmailAddr == NULL ) {
  1.1290 +			rawEmailAddr = CERT_GetNameElement(cert->arena,
  1.1291 +			  &(current->name.directoryName), SEC_OID_RFC1274_MAIL);
  1.1292 +		    }
  1.1293 +		} else if (current->type == certRFC822Name) {
  1.1294 +		    rawEmailAddr = (char*)PORT_ArenaZAlloc(cert->arena,
  1.1295 +						current->name.other.len + 1);
  1.1296 +		    if (!rawEmailAddr) {
  1.1297 +			goto finish;
  1.1298 +		    }
  1.1299 +		    PORT_Memcpy(rawEmailAddr, current->name.other.data, 
  1.1300 +				current->name.other.len);
  1.1301 +		    rawEmailAddr[current->name.other.len] = '\0';
  1.1302 +		}
  1.1303 +		if (rawEmailAddr) {
  1.1304 +		    break;
  1.1305 +		}
  1.1306 +		current = CERT_GetNextGeneralName(current);
  1.1307 +	    } while (current != nameList);
  1.1308 +	}
  1.1309 +    }
  1.1310 +    if (rawEmailAddr) {
  1.1311 +	for (i = 0; i <= (int) PORT_Strlen(rawEmailAddr); i++) {
  1.1312 +	    rawEmailAddr[i] = tolower(rawEmailAddr[i]);
  1.1313 +	}
  1.1314 +    } 
  1.1315 +
  1.1316 +finish:
  1.1317 +
  1.1318 +    /* Don't free nameList, it's part of the arena. */
  1.1319 +
  1.1320 +    if (arena) {
  1.1321 +	PORT_FreeArena(arena, PR_FALSE);
  1.1322 +    }
  1.1323 +
  1.1324 +    if ( subAltName.data ) {
  1.1325 +	SECITEM_FreeItem(&subAltName, PR_FALSE);
  1.1326 +    }
  1.1327 +
  1.1328 +    return(rawEmailAddr);
  1.1329 +}
  1.1330 +
  1.1331 +static char *
  1.1332 +appendStringToBuf(char *dest, char *src, PRUint32 *pRemaining)
  1.1333 +{
  1.1334 +    PRUint32 len;
  1.1335 +    if (dest && src && src[0] && *pRemaining > (len = PL_strlen(src))) {
  1.1336 +	PRUint32 i;
  1.1337 +	for (i = 0; i < len; ++i)
  1.1338 +	    dest[i] = tolower(src[i]);
  1.1339 +	dest[len] = 0;
  1.1340 +	dest        += len + 1;
  1.1341 +	*pRemaining -= len + 1;
  1.1342 +    }
  1.1343 +    return dest;
  1.1344 +}
  1.1345 +
  1.1346 +#undef NEEDS_HEX_ESCAPE
  1.1347 +#define NEEDS_HEX_ESCAPE(c) (c < 0x20)
  1.1348 +
  1.1349 +static char *
  1.1350 +appendItemToBuf(char *dest, SECItem *src, PRUint32 *pRemaining)
  1.1351 +{
  1.1352 +    if (dest && src && src->data && src->len && src->data[0]) {
  1.1353 +	PRUint32 len = src->len;
  1.1354 +	PRUint32 i;
  1.1355 +	PRUint32 reqLen = len + 1;
  1.1356 +	/* are there any embedded control characters ? */
  1.1357 +	for (i = 0; i < len; i++) {
  1.1358 +	    if (NEEDS_HEX_ESCAPE(src->data[i]))
  1.1359 +	    	reqLen += 2;   
  1.1360 +	}
  1.1361 +	if (*pRemaining > reqLen) {
  1.1362 +	    for (i = 0; i < len; ++i) {
  1.1363 +		PRUint8 c = src->data[i];
  1.1364 +		if (NEEDS_HEX_ESCAPE(c)) {
  1.1365 +		    *dest++ = C_BACKSLASH;
  1.1366 +		    *dest++ = hexChars[ (c >> 4) & 0x0f ];
  1.1367 +		    *dest++ = hexChars[  c       & 0x0f ];
  1.1368 +		} else {
  1.1369 +		    *dest++ = tolower(c);
  1.1370 +	    	}
  1.1371 +	    }
  1.1372 +	    *dest++ = '\0';
  1.1373 +	    *pRemaining -= reqLen;
  1.1374 +	}
  1.1375 +    }
  1.1376 +    return dest;
  1.1377 +}
  1.1378 +
  1.1379 +/* Returns a pointer to an environment-like string, a series of 
  1.1380 +** null-terminated strings, terminated by a zero-length string.
  1.1381 +** This function is intended to be internal to NSS.
  1.1382 +*/
  1.1383 +char *
  1.1384 +cert_GetCertificateEmailAddresses(CERTCertificate *cert)
  1.1385 +{
  1.1386 +    char *           rawEmailAddr = NULL;
  1.1387 +    char *           addrBuf      = NULL;
  1.1388 +    char *           pBuf         = NULL;
  1.1389 +    PLArenaPool *    tmpArena     = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.1390 +    PRUint32         maxLen       = 0;
  1.1391 +    PRInt32          finalLen     = 0;
  1.1392 +    SECStatus        rv;
  1.1393 +    SECItem          subAltName;
  1.1394 +    
  1.1395 +    if (!tmpArena) 
  1.1396 +    	return addrBuf;
  1.1397 +
  1.1398 +    subAltName.data = NULL;
  1.1399 +    maxLen = cert->derCert.len;
  1.1400 +    PORT_Assert(maxLen);
  1.1401 +    if (!maxLen) 
  1.1402 +	maxLen = 2000;  /* a guess, should never happen */
  1.1403 +
  1.1404 +    pBuf = addrBuf = (char *)PORT_ArenaZAlloc(tmpArena, maxLen + 1);
  1.1405 +    if (!addrBuf) 
  1.1406 +    	goto loser;
  1.1407 +
  1.1408 +    rawEmailAddr = CERT_GetNameElement(tmpArena, &cert->subject,
  1.1409 +				       SEC_OID_PKCS9_EMAIL_ADDRESS);
  1.1410 +    pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
  1.1411 +
  1.1412 +    rawEmailAddr = CERT_GetNameElement(tmpArena, &cert->subject, 
  1.1413 +				       SEC_OID_RFC1274_MAIL);
  1.1414 +    pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
  1.1415 +
  1.1416 +    rv = CERT_FindCertExtension(cert,  SEC_OID_X509_SUBJECT_ALT_NAME, 
  1.1417 +				&subAltName);
  1.1418 +    if (rv == SECSuccess && subAltName.data) {
  1.1419 +	CERTGeneralName *nameList     = NULL;
  1.1420 +
  1.1421 +	if (!!(nameList = CERT_DecodeAltNameExtension(tmpArena, &subAltName))) {
  1.1422 +	    CERTGeneralName *current = nameList;
  1.1423 +	    do {
  1.1424 +		if (current->type == certDirectoryName) {
  1.1425 +		    rawEmailAddr = CERT_GetNameElement(tmpArena,
  1.1426 +			                       &current->name.directoryName, 
  1.1427 +					       SEC_OID_PKCS9_EMAIL_ADDRESS);
  1.1428 +		    pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
  1.1429 +
  1.1430 +		    rawEmailAddr = CERT_GetNameElement(tmpArena,
  1.1431 +					      &current->name.directoryName, 
  1.1432 +					      SEC_OID_RFC1274_MAIL);
  1.1433 +		    pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
  1.1434 +		} else if (current->type == certRFC822Name) {
  1.1435 +		    pBuf = appendItemToBuf(pBuf, &current->name.other, &maxLen);
  1.1436 +		}
  1.1437 +		current = CERT_GetNextGeneralName(current);
  1.1438 +	    } while (current != nameList);
  1.1439 +	}
  1.1440 +	SECITEM_FreeItem(&subAltName, PR_FALSE);
  1.1441 +	/* Don't free nameList, it's part of the tmpArena. */
  1.1442 +    }
  1.1443 +    /* now copy superstring to cert's arena */
  1.1444 +    finalLen = (pBuf - addrBuf) + 1;
  1.1445 +    pBuf = NULL;
  1.1446 +    if (finalLen > 1) {
  1.1447 +	pBuf = PORT_ArenaAlloc(cert->arena, finalLen);
  1.1448 +	if (pBuf) {
  1.1449 +	    PORT_Memcpy(pBuf, addrBuf, finalLen);
  1.1450 +	}
  1.1451 +    }
  1.1452 +loser:
  1.1453 +    if (tmpArena)
  1.1454 +	PORT_FreeArena(tmpArena, PR_FALSE);
  1.1455 +
  1.1456 +    return pBuf;
  1.1457 +}
  1.1458 +
  1.1459 +/* returns pointer to storage in cert's arena.  Storage remains valid
  1.1460 +** as long as cert's reference count doesn't go to zero.
  1.1461 +** Caller should strdup or otherwise copy.
  1.1462 +*/
  1.1463 +const char *	/* const so caller won't muck with it. */
  1.1464 +CERT_GetFirstEmailAddress(CERTCertificate * cert)
  1.1465 +{
  1.1466 +    if (cert && cert->emailAddr && cert->emailAddr[0])
  1.1467 +    	return (const char *)cert->emailAddr;
  1.1468 +    return NULL;
  1.1469 +}
  1.1470 +
  1.1471 +/* returns pointer to storage in cert's arena.  Storage remains valid
  1.1472 +** as long as cert's reference count doesn't go to zero.
  1.1473 +** Caller should strdup or otherwise copy.
  1.1474 +*/
  1.1475 +const char *	/* const so caller won't muck with it. */
  1.1476 +CERT_GetNextEmailAddress(CERTCertificate * cert, const char * prev)
  1.1477 +{
  1.1478 +    if (cert && prev && prev[0]) {
  1.1479 +    	PRUint32 len = PL_strlen(prev);
  1.1480 +	prev += len + 1;
  1.1481 +	if (prev && prev[0])
  1.1482 +	    return prev;
  1.1483 +    }
  1.1484 +    return NULL;
  1.1485 +}
  1.1486 +
  1.1487 +/* This is seriously bogus, now that certs store their email addresses in
  1.1488 +** subject Alternative Name extensions. 
  1.1489 +** Returns a string allocated by PORT_StrDup, which the caller must free.
  1.1490 +*/
  1.1491 +char *
  1.1492 +CERT_GetCertEmailAddress(const CERTName *name)
  1.1493 +{
  1.1494 +    char *rawEmailAddr;
  1.1495 +    char *emailAddr;
  1.1496 +
  1.1497 +    
  1.1498 +    rawEmailAddr = CERT_GetNameElement(NULL, name, SEC_OID_PKCS9_EMAIL_ADDRESS);
  1.1499 +    if ( rawEmailAddr == NULL ) {
  1.1500 +	rawEmailAddr = CERT_GetNameElement(NULL, name, SEC_OID_RFC1274_MAIL);
  1.1501 +    }
  1.1502 +    emailAddr = CERT_FixupEmailAddr(rawEmailAddr);
  1.1503 +    if ( rawEmailAddr ) {
  1.1504 +	PORT_Free(rawEmailAddr);
  1.1505 +    }
  1.1506 +    return(emailAddr);
  1.1507 +}
  1.1508 +
  1.1509 +/* The return value must be freed with PORT_Free. */
  1.1510 +char *
  1.1511 +CERT_GetCommonName(const CERTName *name)
  1.1512 +{
  1.1513 +    return(CERT_GetLastNameElement(NULL, name, SEC_OID_AVA_COMMON_NAME));
  1.1514 +}
  1.1515 +
  1.1516 +char *
  1.1517 +CERT_GetCountryName(const CERTName *name)
  1.1518 +{
  1.1519 +    return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_COUNTRY_NAME));
  1.1520 +}
  1.1521 +
  1.1522 +char *
  1.1523 +CERT_GetLocalityName(const CERTName *name)
  1.1524 +{
  1.1525 +    return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_LOCALITY));
  1.1526 +}
  1.1527 +
  1.1528 +char *
  1.1529 +CERT_GetStateName(const CERTName *name)
  1.1530 +{
  1.1531 +    return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_STATE_OR_PROVINCE));
  1.1532 +}
  1.1533 +
  1.1534 +char *
  1.1535 +CERT_GetOrgName(const CERTName *name)
  1.1536 +{
  1.1537 +    return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_ORGANIZATION_NAME));
  1.1538 +}
  1.1539 +
  1.1540 +char *
  1.1541 +CERT_GetDomainComponentName(const CERTName *name)
  1.1542 +{
  1.1543 +    return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_DC));
  1.1544 +}
  1.1545 +
  1.1546 +char *
  1.1547 +CERT_GetOrgUnitName(const CERTName *name)
  1.1548 +{
  1.1549 +    return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME));
  1.1550 +}
  1.1551 +
  1.1552 +char *
  1.1553 +CERT_GetDnQualifier(const CERTName *name)
  1.1554 +{
  1.1555 +    return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_DN_QUALIFIER));
  1.1556 +}
  1.1557 +
  1.1558 +char *
  1.1559 +CERT_GetCertUid(const CERTName *name)
  1.1560 +{
  1.1561 +    return(CERT_GetNameElement(NULL, name, SEC_OID_RFC1274_UID));
  1.1562 +}
  1.1563 +

mercurial