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