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

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

mercurial