diff options
Diffstat (limited to 'security/nss/lib/certdb/alg1485.c')
-rw-r--r-- | security/nss/lib/certdb/alg1485.c | 1555 |
1 files changed, 0 insertions, 1555 deletions
diff --git a/security/nss/lib/certdb/alg1485.c b/security/nss/lib/certdb/alg1485.c deleted file mode 100644 index ffdaf9cf9..000000000 --- a/security/nss/lib/certdb/alg1485.c +++ /dev/null @@ -1,1555 +0,0 @@ -/* alg1485.c - implementation of RFCs 1485, 1779 and 2253. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "prprf.h" -#include "cert.h" -#include "certi.h" -#include "xconst.h" -#include "genname.h" -#include "secitem.h" -#include "secerr.h" - -typedef struct NameToKindStr { - const char * name; - unsigned int maxLen; /* max bytes in UTF8 encoded string value */ - SECOidTag kind; - int valueType; -} NameToKind; - -/* local type for directory string--could be printable_string or utf8 */ -#define SEC_ASN1_DS SEC_ASN1_HIGH_TAG_NUMBER - -/* Add new entries to this table, and maybe to function ParseRFC1485AVA */ -static const NameToKind name2kinds[] = { -/* IANA registered type names - * (See: http://www.iana.org/assignments/ldap-parameters) - */ -/* RFC 3280, 4630 MUST SUPPORT */ - { "CN", 64, SEC_OID_AVA_COMMON_NAME, SEC_ASN1_DS}, - { "ST", 128, SEC_OID_AVA_STATE_OR_PROVINCE, - SEC_ASN1_DS}, - { "O", 64, SEC_OID_AVA_ORGANIZATION_NAME, - SEC_ASN1_DS}, - { "OU", 64, SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME, - SEC_ASN1_DS}, - { "dnQualifier", 32767, SEC_OID_AVA_DN_QUALIFIER, SEC_ASN1_PRINTABLE_STRING}, - { "C", 2, SEC_OID_AVA_COUNTRY_NAME, SEC_ASN1_PRINTABLE_STRING}, - { "serialNumber", 64, SEC_OID_AVA_SERIAL_NUMBER,SEC_ASN1_PRINTABLE_STRING}, - -/* RFC 3280, 4630 SHOULD SUPPORT */ - { "L", 128, SEC_OID_AVA_LOCALITY, SEC_ASN1_DS}, - { "title", 64, SEC_OID_AVA_TITLE, SEC_ASN1_DS}, - { "SN", 64, SEC_OID_AVA_SURNAME, SEC_ASN1_DS}, - { "givenName", 64, SEC_OID_AVA_GIVEN_NAME, SEC_ASN1_DS}, - { "initials", 64, SEC_OID_AVA_INITIALS, SEC_ASN1_DS}, - { "generationQualifier", - 64, SEC_OID_AVA_GENERATION_QUALIFIER, - SEC_ASN1_DS}, -/* RFC 3280, 4630 MAY SUPPORT */ - { "DC", 128, SEC_OID_AVA_DC, SEC_ASN1_IA5_STRING}, - { "MAIL", 256, SEC_OID_RFC1274_MAIL, SEC_ASN1_IA5_STRING}, - { "UID", 256, SEC_OID_RFC1274_UID, SEC_ASN1_DS}, - -/* ------------------ "strict" boundary --------------------------------- - * In strict mode, cert_NameToAscii does not encode any of the attributes - * below this line. The first SECOidTag below this line must be used to - * conditionally define the "endKind" in function AppendAVA() below. - * Most new attribute names should be added below this line. - * Maybe this line should be up higher? Say, after the 3280 MUSTs and - * before the 3280 SHOULDs? - */ - -/* values from draft-ietf-ldapbis-user-schema-05 (not in RFC 3280) */ - { "postalAddress", 128, SEC_OID_AVA_POSTAL_ADDRESS, SEC_ASN1_DS}, - { "postalCode", 40, SEC_OID_AVA_POSTAL_CODE, SEC_ASN1_DS}, - { "postOfficeBox", 40, SEC_OID_AVA_POST_OFFICE_BOX,SEC_ASN1_DS}, - { "houseIdentifier",64, SEC_OID_AVA_HOUSE_IDENTIFIER,SEC_ASN1_DS}, -/* end of IANA registered type names */ - -/* legacy keywords */ - { "E", 128, SEC_OID_PKCS9_EMAIL_ADDRESS,SEC_ASN1_IA5_STRING}, - { "STREET", 128, SEC_OID_AVA_STREET_ADDRESS, SEC_ASN1_DS}, - { "pseudonym", 64, SEC_OID_AVA_PSEUDONYM, SEC_ASN1_DS}, - -/* values defined by the CAB Forum for EV */ - { "incorporationLocality", 128, SEC_OID_EV_INCORPORATION_LOCALITY, - SEC_ASN1_DS}, - { "incorporationState", 128, SEC_OID_EV_INCORPORATION_STATE, - SEC_ASN1_DS}, - { "incorporationCountry", 2, SEC_OID_EV_INCORPORATION_COUNTRY, - SEC_ASN1_PRINTABLE_STRING}, - { "businessCategory", 64, SEC_OID_BUSINESS_CATEGORY, SEC_ASN1_DS}, - - { 0, 256, SEC_OID_UNKNOWN, 0}, -}; - -/* Table facilitates conversion of ASCII hex to binary. */ -static const PRInt16 x2b[256] = { -/* #0x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -/* #1x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -/* #2x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -/* #3x */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -/* #4x */ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -/* #5x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -/* #6x */ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -/* #7x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -/* #8x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -/* #9x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -/* #ax */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -/* #bx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -/* #cx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -/* #dx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -/* #ex */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -/* #fx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 -}; - -#define IS_HEX(c) (x2b[(PRUint8)(c)] >= 0) - -#define C_DOUBLE_QUOTE '\042' - -#define C_BACKSLASH '\134' - -#define C_EQUAL '=' - -#define OPTIONAL_SPACE(c) \ - (((c) == ' ') || ((c) == '\r') || ((c) == '\n')) - -#define SPECIAL_CHAR(c) \ - (((c) == ',') || ((c) == '=') || ((c) == C_DOUBLE_QUOTE) || \ - ((c) == '\r') || ((c) == '\n') || ((c) == '+') || \ - ((c) == '<') || ((c) == '>') || ((c) == '#') || \ - ((c) == ';') || ((c) == C_BACKSLASH)) - - -#define IS_PRINTABLE(c) \ - ((((c) >= 'a') && ((c) <= 'z')) || \ - (((c) >= 'A') && ((c) <= 'Z')) || \ - (((c) >= '0') && ((c) <= '9')) || \ - ((c) == ' ') || \ - ((c) == '\'') || \ - ((c) == '\050') || /* ( */ \ - ((c) == '\051') || /* ) */ \ - (((c) >= '+') && ((c) <= '/')) || /* + , - . / */ \ - ((c) == ':') || \ - ((c) == '=') || \ - ((c) == '?')) - -/* RFC 2253 says we must escape ",+\"\\<>;=" EXCEPT inside a quoted string. - * Inside a quoted string, we only need to escape " and \ - * We choose to quote strings containing any of those special characters, - * so we only need to escape " and \ - */ -#define NEEDS_ESCAPE(c) \ - (c == C_DOUBLE_QUOTE || c == C_BACKSLASH) - -#define NEEDS_HEX_ESCAPE(c) \ - ((PRUint8)c < 0x20 || c == 0x7f) - -int -cert_AVAOidTagToMaxLen(SECOidTag tag) -{ - const NameToKind *n2k = name2kinds; - - while (n2k->kind != tag && n2k->kind != SEC_OID_UNKNOWN) { - ++n2k; - } - return (n2k->kind != SEC_OID_UNKNOWN) ? n2k->maxLen : -1; -} - -static PRBool -IsPrintable(unsigned char *data, unsigned len) -{ - unsigned char ch, *end; - - end = data + len; - while (data < end) { - ch = *data++; - if (!IS_PRINTABLE(ch)) { - return PR_FALSE; - } - } - return PR_TRUE; -} - -static void -skipSpace(const char **pbp, const char *endptr) -{ - const char *bp = *pbp; - while (bp < endptr && OPTIONAL_SPACE(*bp)) { - bp++; - } - *pbp = bp; -} - -static SECStatus -scanTag(const char **pbp, const char *endptr, char *tagBuf, int tagBufSize) -{ - const char *bp; - char *tagBufp; - int taglen; - - PORT_Assert(tagBufSize > 0); - - /* skip optional leading space */ - skipSpace(pbp, endptr); - if (*pbp == endptr) { - /* nothing left */ - return SECFailure; - } - - /* fill tagBuf */ - taglen = 0; - bp = *pbp; - tagBufp = tagBuf; - while (bp < endptr && !OPTIONAL_SPACE(*bp) && (*bp != C_EQUAL)) { - if (++taglen >= tagBufSize) { - *pbp = bp; - return SECFailure; - } - *tagBufp++ = *bp++; - } - /* null-terminate tagBuf -- guaranteed at least one space left */ - *tagBufp++ = 0; - *pbp = bp; - - /* skip trailing spaces till we hit something - should be an equal sign */ - skipSpace(pbp, endptr); - if (*pbp == endptr) { - /* nothing left */ - return SECFailure; - } - if (**pbp != C_EQUAL) { - /* should be an equal sign */ - return SECFailure; - } - /* skip over the equal sign */ - (*pbp)++; - - return SECSuccess; -} - -/* Returns the number of bytes in the value. 0 means failure. */ -static int -scanVal(const char **pbp, const char *endptr, char *valBuf, int valBufSize) -{ - const char *bp; - char *valBufp; - int vallen = 0; - PRBool isQuoted; - - PORT_Assert(valBufSize > 0); - - /* skip optional leading space */ - skipSpace(pbp, endptr); - if(*pbp == endptr) { - /* nothing left */ - return 0; - } - - bp = *pbp; - - /* quoted? */ - if (*bp == C_DOUBLE_QUOTE) { - isQuoted = PR_TRUE; - /* skip over it */ - bp++; - } else { - isQuoted = PR_FALSE; - } - - valBufp = valBuf; - while (bp < endptr) { - char c = *bp; - if (c == C_BACKSLASH) { - /* escape character */ - bp++; - if (bp >= endptr) { - /* escape charater must appear with paired char */ - *pbp = bp; - return 0; - } - c = *bp; - if (IS_HEX(c) && (endptr - bp) >= 2 && IS_HEX(bp[1])) { - bp++; - c = (char)((x2b[(PRUint8)c] << 4) | x2b[(PRUint8)*bp]); - } - } else if (c == '#' && bp == *pbp) { - /* ignore leading #, quotation not required for it. */ - } else if (!isQuoted && SPECIAL_CHAR(c)) { - /* unescaped special and not within quoted value */ - break; - } else if (c == C_DOUBLE_QUOTE) { - /* reached unescaped double quote */ - break; - } - /* append character */ - vallen++; - if (vallen >= valBufSize) { - *pbp = bp; - return 0; - } - *valBufp++ = c; - bp++; - } - - /* strip trailing spaces from unquoted values */ - if (!isQuoted) { - while (valBufp > valBuf) { - char c = valBufp[-1]; - if (! OPTIONAL_SPACE(c)) - break; - --valBufp; - } - vallen = valBufp - valBuf; - } - - if (isQuoted) { - /* insist that we stopped on a double quote */ - if (*bp != C_DOUBLE_QUOTE) { - *pbp = bp; - return 0; - } - /* skip over the quote and skip optional space */ - bp++; - skipSpace(&bp, endptr); - } - - *pbp = bp; - - /* null-terminate valBuf -- guaranteed at least one space left */ - *valBufp = 0; - - return vallen; -} - -/* Caller must set error code upon failure */ -static SECStatus -hexToBin(PLArenaPool *pool, SECItem * destItem, const char * src, int len) -{ - PRUint8 * dest; - - destItem->data = NULL; - if (len <= 0 || (len & 1)) { - goto loser; - } - len >>= 1; - if (!SECITEM_AllocItem(pool, destItem, len)) - goto loser; - dest = destItem->data; - for (; len > 0; len--, src += 2) { - PRInt16 bin = (x2b[(PRUint8)src[0]] << 4) | x2b[(PRUint8)src[1]]; - if (bin < 0) - goto loser; - *dest++ = (PRUint8)bin; - } - return SECSuccess; -loser: - if (!pool) - SECITEM_FreeItem(destItem, PR_FALSE); - return SECFailure; -} - -/* Parses one AVA, starting at *pbp. Stops at endptr. - * Advances *pbp past parsed AVA and trailing separator (if present). - * On any error, returns NULL and *pbp is undefined. - * On success, returns CERTAVA allocated from arena, and (*pbp)[-1] was - * the last character parsed. *pbp is either equal to endptr or - * points to first character after separator. - */ -static CERTAVA * -ParseRFC1485AVA(PRArenaPool *arena, const char **pbp, const char *endptr) -{ - CERTAVA *a; - const NameToKind *n2k; - const char *bp; - int vt = -1; - int valLen; - SECOidTag kind = SEC_OID_UNKNOWN; - SECStatus rv = SECFailure; - SECItem derOid = { 0, NULL, 0 }; - SECItem derVal = { 0, NULL, 0}; - char sep = 0; - - char tagBuf[32]; - char valBuf[384]; - - PORT_Assert(arena); - if (SECSuccess != scanTag(pbp, endptr, tagBuf, sizeof tagBuf) || - !(valLen = scanVal(pbp, endptr, valBuf, sizeof valBuf))) { - goto loser; - } - - bp = *pbp; - if (bp < endptr) { - sep = *bp++; /* skip over separator */ - } - *pbp = bp; - /* if we haven't finished, insist that we've stopped on a separator */ - if (sep && sep != ',' && sep != ';' && sep != '+') { - goto loser; - } - - /* is this a dotted decimal OID attribute type ? */ - if (!PL_strncasecmp("oid.", tagBuf, 4)) { - rv = SEC_StringToOID(arena, &derOid, tagBuf, strlen(tagBuf)); - } else { - for (n2k = name2kinds; n2k->name; n2k++) { - SECOidData *oidrec; - if (PORT_Strcasecmp(n2k->name, tagBuf) == 0) { - kind = n2k->kind; - vt = n2k->valueType; - oidrec = SECOID_FindOIDByTag(kind); - if (oidrec == NULL) - goto loser; - derOid = oidrec->oid; - break; - } - } - } - if (kind == SEC_OID_UNKNOWN && rv != SECSuccess) - goto loser; - - /* Is this a hex encoding of a DER attribute value ? */ - if ('#' == valBuf[0]) { - /* convert attribute value from hex to binary */ - rv = hexToBin(arena, &derVal, valBuf + 1, valLen - 1); - if (rv) - goto loser; - a = CERT_CreateAVAFromRaw(arena, &derOid, &derVal); - } else { - if (kind == SEC_OID_UNKNOWN) - goto loser; - if (kind == SEC_OID_AVA_COUNTRY_NAME && valLen != 2) - goto loser; - if (vt == SEC_ASN1_PRINTABLE_STRING && - !IsPrintable((unsigned char*) valBuf, valLen)) - goto loser; - if (vt == SEC_ASN1_DS) { - /* RFC 4630: choose PrintableString or UTF8String */ - if (IsPrintable((unsigned char*) valBuf, valLen)) - vt = SEC_ASN1_PRINTABLE_STRING; - else - vt = SEC_ASN1_UTF8_STRING; - } - - derVal.data = (unsigned char*) valBuf; - derVal.len = valLen; - a = CERT_CreateAVAFromSECItem(arena, kind, vt, &derVal); - } - return a; - -loser: - /* matched no kind -- invalid tag */ - PORT_SetError(SEC_ERROR_INVALID_AVA); - return 0; -} - -static CERTName * -ParseRFC1485Name(const char *buf, int len) -{ - SECStatus rv; - CERTName *name; - const char *bp, *e; - CERTAVA *ava; - CERTRDN *rdn = NULL; - - name = CERT_CreateName(NULL); - if (name == NULL) { - return NULL; - } - - e = buf + len; - bp = buf; - while (bp < e) { - ava = ParseRFC1485AVA(name->arena, &bp, e); - if (ava == 0) - goto loser; - if (!rdn) { - rdn = CERT_CreateRDN(name->arena, ava, (CERTAVA *)0); - if (rdn == 0) - goto loser; - rv = CERT_AddRDN(name, rdn); - } else { - rv = CERT_AddAVA(name->arena, rdn, ava); - } - if (rv) - goto loser; - if (bp[-1] != '+') - rdn = NULL; /* done with this RDN */ - skipSpace(&bp, e); - } - - if (name->rdns[0] == 0) { - /* empty name -- illegal */ - goto loser; - } - - /* Reverse order of RDNS to comply with RFC */ - { - CERTRDN **firstRdn; - CERTRDN **lastRdn; - CERTRDN *tmp; - - /* get first one */ - firstRdn = name->rdns; - - /* find last one */ - lastRdn = name->rdns; - while (*lastRdn) lastRdn++; - lastRdn--; - - /* reverse list */ - for ( ; firstRdn < lastRdn; firstRdn++, lastRdn--) { - tmp = *firstRdn; - *firstRdn = *lastRdn; - *lastRdn = tmp; - } - } - - /* return result */ - return name; - - loser: - CERT_DestroyName(name); - return NULL; -} - -CERTName * -CERT_AsciiToName(const char *string) -{ - CERTName *name; - name = ParseRFC1485Name(string, PORT_Strlen(string)); - return name; -} - -/************************************************************************/ - -typedef struct stringBufStr { - char *buffer; - unsigned offset; - unsigned size; -} stringBuf; - -#define DEFAULT_BUFFER_SIZE 200 - -static SECStatus -AppendStr(stringBuf *bufp, char *str) -{ - char *buf; - unsigned bufLen, bufSize, len; - int size = 0; - - /* Figure out how much to grow buf by (add in the '\0') */ - buf = bufp->buffer; - bufLen = bufp->offset; - len = PORT_Strlen(str); - bufSize = bufLen + len; - if (!buf) { - bufSize++; - size = PR_MAX(DEFAULT_BUFFER_SIZE,bufSize*2); - buf = (char *) PORT_Alloc(size); - bufp->size = size; - } else if (bufp->size < bufSize) { - size = bufSize*2; - buf =(char *) PORT_Realloc(buf,size); - bufp->size = size; - } - if (!buf) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - return SECFailure; - } - bufp->buffer = buf; - bufp->offset = bufSize; - - /* Concatenate str onto buf */ - buf = buf + bufLen; - if (bufLen) buf--; /* stomp on old '\0' */ - PORT_Memcpy(buf, str, len+1); /* put in new null */ - return SECSuccess; -} - -typedef enum { - minimalEscape = 0, /* only hex escapes, and " and \ */ - minimalEscapeAndQuote, /* as above, plus quoting */ - fullEscape /* no quoting, full escaping */ -} EQMode; - -/* Some characters must be escaped as a hex string, e.g. c -> \nn . - * Others must be escaped by preceding with a '\', e.g. c -> \c , but - * there are certain "special characters" that may be handled by either - * escaping them, or by enclosing the entire attribute value in quotes. - * A NULL value for pEQMode implies selecting minimalEscape mode. - * Some callers will do quoting when needed, others will not. - * If a caller selects minimalEscapeAndQuote, and the string does not - * need quoting, then this function changes it to minimalEscape. - */ -static int -cert_RFC1485_GetRequiredLen(const char *src, int srclen, EQMode *pEQMode) -{ - int i, reqLen=0; - EQMode mode = pEQMode ? *pEQMode : minimalEscape; - PRBool needsQuoting = PR_FALSE; - char lastC = 0; - - /* need to make an initial pass to determine if quoting is needed */ - for (i = 0; i < srclen; i++) { - char c = src[i]; - reqLen++; - if (NEEDS_HEX_ESCAPE(c)) { /* c -> \xx */ - reqLen += 2; - } else if (NEEDS_ESCAPE(c)) { /* c -> \c */ - reqLen++; - } else if (SPECIAL_CHAR(c)) { - if (mode == minimalEscapeAndQuote) /* quoting is allowed */ - needsQuoting = PR_TRUE; /* entirety will need quoting */ - else if (mode == fullEscape) - reqLen++; /* MAY escape this character */ - } else if (OPTIONAL_SPACE(c) && OPTIONAL_SPACE(lastC)) { - if (mode == minimalEscapeAndQuote) /* quoting is allowed */ - needsQuoting = PR_TRUE; /* entirety will need quoting */ - } - lastC = c; - } - /* if it begins or ends in optional space it needs quoting */ - if (!needsQuoting && srclen > 0 && mode == minimalEscapeAndQuote && - (OPTIONAL_SPACE(src[srclen-1]) || OPTIONAL_SPACE(src[0]))) { - needsQuoting = PR_TRUE; - } - - if (needsQuoting) - reqLen += 2; - if (pEQMode && mode == minimalEscapeAndQuote && !needsQuoting) - *pEQMode = minimalEscape; - return reqLen; -} - -static const char hexChars[16] = { "0123456789abcdef" }; - -static SECStatus -escapeAndQuote(char *dst, int dstlen, char *src, int srclen, EQMode *pEQMode) -{ - int i, reqLen=0; - EQMode mode = pEQMode ? *pEQMode : minimalEscape; - - /* space for terminal null */ - reqLen = cert_RFC1485_GetRequiredLen(src, srclen, &mode) + 1; - if (reqLen > dstlen) { - PORT_SetError(SEC_ERROR_OUTPUT_LEN); - return SECFailure; - } - - if (mode == minimalEscapeAndQuote) - *dst++ = C_DOUBLE_QUOTE; - for (i = 0; i < srclen; i++) { - char c = src[i]; - if (NEEDS_HEX_ESCAPE(c)) { - *dst++ = C_BACKSLASH; - *dst++ = hexChars[ (c >> 4) & 0x0f ]; - *dst++ = hexChars[ c & 0x0f ]; - } else { - if (NEEDS_ESCAPE(c) || (SPECIAL_CHAR(c) && mode == fullEscape)) { - *dst++ = C_BACKSLASH; - } - *dst++ = c; - } - } - if (mode == minimalEscapeAndQuote) - *dst++ = C_DOUBLE_QUOTE; - *dst++ = 0; - if (pEQMode) - *pEQMode = mode; - return SECSuccess; -} - -SECStatus -CERT_RFC1485_EscapeAndQuote(char *dst, int dstlen, char *src, int srclen) -{ - EQMode mode = minimalEscapeAndQuote; - return escapeAndQuote(dst, dstlen, src, srclen, &mode); -} - - -/* convert an OID to dotted-decimal representation */ -/* Returns a string that must be freed with PR_smprintf_free(), */ -char * -CERT_GetOidString(const SECItem *oid) -{ - PRUint8 *stop; /* points to first byte after OID string */ - PRUint8 *first; /* byte of an OID component integer */ - PRUint8 *last; /* byte of an OID component integer */ - char *rvString = NULL; - char *prefix = NULL; - -#define MAX_OID_LEN 1024 /* bytes */ - - if (oid->len > MAX_OID_LEN) { - PORT_SetError(SEC_ERROR_INPUT_LEN); - return NULL; - } - - /* first will point to the next sequence of bytes to decode */ - first = (PRUint8 *)oid->data; - /* stop points to one past the legitimate data */ - stop = &first[ oid->len ]; - - /* - * Check for our pseudo-encoded single-digit OIDs - */ - if ((*first == 0x80) && (2 == oid->len)) { - /* Funky encoding. The second byte is the number */ - rvString = PR_smprintf("%lu", (PRUint32)first[1]); - if (!rvString) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - } - return rvString; - } - - for (; first < stop; first = last + 1) { - unsigned int bytesBeforeLast; - - for (last = first; last < stop; last++) { - if (0 == (*last & 0x80)) { - break; - } - } - bytesBeforeLast = (unsigned int)(last - first); - if (bytesBeforeLast <= 3U) { /* 0-28 bit number */ - PRUint32 n = 0; - PRUint32 c; - -#define CGET(i, m) \ - c = last[-i] & m; \ - n |= c << (7 * i) - -#define CASE(i, m) \ - case i: \ - CGET(i, m); \ - if (!n) goto unsupported \ - /* fall-through */ - - switch (bytesBeforeLast) { - CASE(3, 0x7f); - CASE(2, 0x7f); - CASE(1, 0x7f); - case 0: n |= last[0] & 0x7f; - break; - } - if (last[0] & 0x80) - goto unsupported; - - if (!rvString) { - /* This is the first number.. decompose it */ - PRUint32 one = PR_MIN(n/40, 2); /* never > 2 */ - PRUint32 two = n - (one * 40); - - rvString = PR_smprintf("OID.%lu.%lu", one, two); - } else { - prefix = rvString; - rvString = PR_smprintf("%s.%lu", prefix, n); - } - } else if (bytesBeforeLast <= 9U) { /* 29-64 bit number */ - PRUint64 n = 0; - PRUint64 c; - - switch (bytesBeforeLast) { - CASE(9, 0x01); - CASE(8, 0x7f); - CASE(7, 0x7f); - CASE(6, 0x7f); - CASE(5, 0x7f); - CASE(4, 0x7f); - CGET(3, 0x7f); - CGET(2, 0x7f); - CGET(1, 0x7f); - CGET(0, 0x7f); - break; - } - if (last[0] & 0x80) - goto unsupported; - - if (!rvString) { - /* This is the first number.. decompose it */ - PRUint64 one = PR_MIN(n/40, 2); /* never > 2 */ - PRUint64 two = n - (one * 40); - - rvString = PR_smprintf("OID.%llu.%llu", one, two); - } else { - prefix = rvString; - rvString = PR_smprintf("%s.%llu", prefix, n); - } - } else { - /* More than a 64-bit number, or not minimal encoding. */ -unsupported: - if (!rvString) - rvString = PR_smprintf("OID.UNSUPPORTED"); - else { - prefix = rvString; - rvString = PR_smprintf("%s.UNSUPPORTED", prefix); - } - } - - if (prefix) { - PR_smprintf_free(prefix); - prefix = NULL; - } - if (!rvString) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - break; - } - } - return rvString; -} - -/* convert DER-encoded hex to a string */ -static SECItem * -get_hex_string(SECItem *data) -{ - SECItem *rv; - unsigned int i, j; - static const char hex[] = { "0123456789ABCDEF" }; - - /* '#' + 2 chars per octet + terminator */ - rv = SECITEM_AllocItem(NULL, NULL, data->len*2 + 2); - if (!rv) { - return NULL; - } - rv->data[0] = '#'; - rv->len = 1 + 2 * data->len; - for (i=0; i<data->len; i++) { - j = data->data[i]; - rv->data[2*i+1] = hex[j >> 4]; - rv->data[2*i+2] = hex[j & 15]; - } - rv->data[rv->len] = 0; - return rv; -} - -/* For compliance with RFC 2253, RFC 3280 and RFC 4630, we choose to - * use the NAME=STRING form, rather than the OID.N.N=#hexXXXX form, - * when both of these conditions are met: - * 1) The attribute name OID (kind) has a known name string that is - * defined in one of those RFCs, or in RFCs that they cite, AND - * 2) The attribute's value encoding is RFC compliant for the kind - * (e.g., the value's encoding tag is correct for the kind, and - * the value's length is in the range allowed for the kind, and - * the value's contents are appropriate for the encoding tag). - * Otherwise, we use the OID.N.N=#hexXXXX form. - * - * If the caller prefers maximum human readability to RFC compliance, - * then - * - We print the kind in NAME= string form if we know the name - * string for the attribute type OID, regardless of whether the - * value is correctly encoded or not. else we use the OID.N.N= form. - * - We use the non-hex STRING form for the attribute value if the - * value can be represented in such a form. Otherwise, we use - * the hex string form. - * This implies that, for maximum human readability, in addition to - * the two forms allowed by the RFC, we allow two other forms of output: - * - the OID.N.N=STRING form, and - * - the NAME=#hexXXXX form - * When the caller prefers maximum human readability, we do not allow - * the value of any attribute to exceed the length allowed by the RFC. - * If the attribute value exceeds the allowed length, we truncate it to - * the allowed length and append "...". - * Also in this case, we arbitrarily impose a limit on the length of the - * entire AVA encoding, regardless of the form, of 384 bytes per AVA. - * This limit includes the trailing NULL character. If the encoded - * AVA length exceeds that limit, this function reports failure to encode - * the AVA. - * - * An ASCII representation of an AVA is said to be "invertible" if - * conversion back to DER reproduces the original DER encoding exactly. - * The RFC 2253 rules do not ensure that all ASCII AVAs derived according - * to its rules are invertible. That is because the RFCs allow some - * attribute values to be encoded in any of a number of encodings, - * and the encoding type information is lost in the non-hex STRING form. - * This is particularly true of attributes of type DirectoryString. - * The encoding type information is always preserved in the hex string - * form, because the hex includes the entire DER encoding of the value. - * - * So, when the caller perfers maximum invertibility, we apply the - * RFC compliance rules stated above, and add a third required - * condition on the use of the NAME=STRING form. - * 3) The attribute's kind is not is allowed to be encoded in any of - * several different encodings, such as DirectoryStrings. - * - * The chief difference between CERT_N2A_STRICT and CERT_N2A_INVERTIBLE - * is that the latter forces DirectoryStrings to be hex encoded. - * - * As a simplification, we assume the value is correctly encoded for - * its encoding type. That is, we do not test that all the characters - * in a string encoded type are allowed by that type. We assume it. - */ -static SECStatus -AppendAVA(stringBuf *bufp, CERTAVA *ava, CertStrictnessLevel strict) -{ -#define TMPBUF_LEN 384 - const NameToKind *pn2k = name2kinds; - SECItem *avaValue = NULL; - char *unknownTag = NULL; - char *encodedAVA = NULL; - PRBool useHex = PR_FALSE; /* use =#hexXXXX form */ - PRBool truncateName = PR_FALSE; - PRBool truncateValue = PR_FALSE; - SECOidTag endKind; - SECStatus rv; - unsigned int len; - unsigned int nameLen, valueLen; - unsigned int maxName, maxValue; - EQMode mode = minimalEscapeAndQuote; - NameToKind n2k = { NULL, 32767, SEC_OID_UNKNOWN, SEC_ASN1_DS }; - char tmpBuf[TMPBUF_LEN]; - -#define tagName n2k.name /* non-NULL means use NAME= form */ -#define maxBytes n2k.maxLen -#define tag n2k.kind -#define vt n2k.valueType - - /* READABLE mode recognizes more names from the name2kinds table - * than do STRICT or INVERTIBLE modes. This assignment chooses the - * point in the table where the attribute type name scanning stops. - */ - endKind = (strict == CERT_N2A_READABLE) ? SEC_OID_UNKNOWN - : SEC_OID_AVA_POSTAL_ADDRESS; - tag = CERT_GetAVATag(ava); - while (pn2k->kind != tag && pn2k->kind != endKind) { - ++pn2k; - } - - if (pn2k->kind != endKind ) { - n2k = *pn2k; - } else if (strict != CERT_N2A_READABLE) { - useHex = PR_TRUE; - } - /* For invertable form, force Directory Strings to use hex form. */ - if (strict == CERT_N2A_INVERTIBLE && vt == SEC_ASN1_DS) { - tagName = NULL; /* must use OID.N form */ - useHex = PR_TRUE; /* must use hex string */ - } - if (!useHex) { - avaValue = CERT_DecodeAVAValue(&ava->value); - if (!avaValue) { - useHex = PR_TRUE; - if (strict != CERT_N2A_READABLE) { - tagName = NULL; /* must use OID.N form */ - } - } - } - if (!tagName) { - /* handle unknown attribute types per RFC 2253 */ - tagName = unknownTag = CERT_GetOidString(&ava->type); - if (!tagName) { - if (avaValue) - SECITEM_FreeItem(avaValue, PR_TRUE); - return SECFailure; - } - } - if (useHex) { - avaValue = get_hex_string(&ava->value); - if (!avaValue) { - if (unknownTag) - PR_smprintf_free(unknownTag); - return SECFailure; - } - } - - nameLen = strlen(tagName); - valueLen = (useHex ? avaValue->len : - cert_RFC1485_GetRequiredLen((char *)avaValue->data, avaValue->len, - &mode)); - len = nameLen + valueLen + 2; /* Add 2 for '=' and trailing NUL */ - - maxName = nameLen; - maxValue = valueLen; - if (len <= sizeof(tmpBuf)) { - encodedAVA = tmpBuf; - } else if (strict != CERT_N2A_READABLE) { - encodedAVA = PORT_Alloc(len); - if (!encodedAVA) { - SECITEM_FreeItem(avaValue, PR_TRUE); - if (unknownTag) - PR_smprintf_free(unknownTag); - return SECFailure; - } - } else { - /* Must make output fit in tmpbuf */ - unsigned int fair = (sizeof tmpBuf)/2 - 1; /* for = and \0 */ - - if (nameLen < fair) { - /* just truncate the value */ - maxValue = (sizeof tmpBuf) - (nameLen + 6); /* for "=...\0", - and possibly '"' */ - } else if (valueLen < fair) { - /* just truncate the name */ - maxName = (sizeof tmpBuf) - (valueLen + 5); /* for "=...\0" */ - } else { - /* truncate both */ - maxName = maxValue = fair - 3; /* for "..." */ - } - if (nameLen > maxName) { - PORT_Assert(unknownTag && unknownTag == tagName); - truncateName = PR_TRUE; - nameLen = maxName; - } - encodedAVA = tmpBuf; - } - - memcpy(encodedAVA, tagName, nameLen); - if (truncateName) { - /* If tag name is too long, we know it is an OID form that was - * allocated from the heap, so we can modify it in place - */ - encodedAVA[nameLen-1] = '.'; - encodedAVA[nameLen-2] = '.'; - encodedAVA[nameLen-3] = '.'; - } - encodedAVA[nameLen++] = '='; - if (unknownTag) - PR_smprintf_free(unknownTag); - - if (strict == CERT_N2A_READABLE && maxValue > maxBytes) - maxValue = maxBytes; - if (valueLen > maxValue) { - valueLen = maxValue; - truncateValue = PR_TRUE; - } - /* escape and quote as necessary - don't quote hex strings */ - if (useHex) { - char * end = encodedAVA + nameLen + valueLen; - memcpy(encodedAVA + nameLen, (char *)avaValue->data, valueLen); - end[0] = '\0'; - if (truncateValue) { - end[-1] = '.'; - end[-2] = '.'; - end[-3] = '.'; - } - rv = SECSuccess; - } else if (!truncateValue) { - rv = escapeAndQuote(encodedAVA + nameLen, len - nameLen, - (char *)avaValue->data, avaValue->len, &mode); - } else { - /* must truncate the escaped and quoted value */ - char bigTmpBuf[TMPBUF_LEN * 3 + 3]; - rv = escapeAndQuote(bigTmpBuf, sizeof bigTmpBuf, - (char *)avaValue->data, valueLen, &mode); - - bigTmpBuf[valueLen--] = '\0'; /* hard stop here */ - /* See if we're in the middle of a multi-byte UTF8 character */ - while (((bigTmpBuf[valueLen] & 0xc0) == 0x80) && valueLen > 0) { - bigTmpBuf[valueLen--] = '\0'; - } - /* add ellipsis to signify truncation. */ - bigTmpBuf[++valueLen] = '.'; - bigTmpBuf[++valueLen] = '.'; - bigTmpBuf[++valueLen] = '.'; - if (bigTmpBuf[0] == '"') - bigTmpBuf[++valueLen] = '"'; - bigTmpBuf[++valueLen] = '\0'; - PORT_Assert(nameLen + valueLen <= (sizeof tmpBuf) - 1); - memcpy(encodedAVA + nameLen, bigTmpBuf, valueLen+1); - } - - SECITEM_FreeItem(avaValue, PR_TRUE); - if (rv == SECSuccess) - rv = AppendStr(bufp, encodedAVA); - if (encodedAVA != tmpBuf) - PORT_Free(encodedAVA); - return rv; -} - -#undef tagName -#undef maxBytes -#undef tag -#undef vt - -char * -CERT_NameToAsciiInvertible(CERTName *name, CertStrictnessLevel strict) -{ - CERTRDN** rdns; - CERTRDN** lastRdn; - CERTRDN** rdn; - PRBool first = PR_TRUE; - stringBuf strBuf = { NULL, 0, 0 }; - - rdns = name->rdns; - if (rdns == NULL) { - return NULL; - } - - /* find last RDN */ - lastRdn = rdns; - while (*lastRdn) lastRdn++; - lastRdn--; - - /* - * Loop over name contents in _reverse_ RDN order appending to string - */ - for (rdn = lastRdn; rdn >= rdns; rdn--) { - CERTAVA** avas = (*rdn)->avas; - CERTAVA* ava; - PRBool newRDN = PR_TRUE; - - /* - * XXX Do we need to traverse the AVAs in reverse order, too? - */ - while (avas && (ava = *avas++) != NULL) { - SECStatus rv; - /* Put in comma or plus separator */ - if (!first) { - /* Use of spaces is deprecated in RFC 2253. */ - rv = AppendStr(&strBuf, newRDN ? "," : "+"); - if (rv) goto loser; - } else { - first = PR_FALSE; - } - - /* Add in tag type plus value into strBuf */ - rv = AppendAVA(&strBuf, ava, strict); - if (rv) goto loser; - newRDN = PR_FALSE; - } - } - return strBuf.buffer; -loser: - if (strBuf.buffer) { - PORT_Free(strBuf.buffer); - } - return NULL; -} - -char * -CERT_NameToAscii(CERTName *name) -{ - return CERT_NameToAsciiInvertible(name, CERT_N2A_READABLE); -} - -/* - * Return the string representation of a DER encoded distinguished name - * "dername" - The DER encoded name to convert - */ -char * -CERT_DerNameToAscii(SECItem *dername) -{ - int rv; - PRArenaPool *arena = NULL; - CERTName name; - char *retstr = NULL; - - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - - if ( arena == NULL) { - goto loser; - } - - rv = SEC_QuickDERDecodeItem(arena, &name, CERT_NameTemplate, dername); - - if ( rv != SECSuccess ) { - goto loser; - } - - retstr = CERT_NameToAscii(&name); - -loser: - if ( arena != NULL ) { - PORT_FreeArena(arena, PR_FALSE); - } - - return(retstr); -} - -static char * -avaToString(PRArenaPool *arena, CERTAVA *ava) -{ - char * buf = NULL; - SECItem* avaValue; - int valueLen; - - avaValue = CERT_DecodeAVAValue(&ava->value); - if(!avaValue) { - return buf; - } - valueLen = cert_RFC1485_GetRequiredLen((char *)avaValue->data, - avaValue->len, NULL) + 1; - if (arena) { - buf = (char *)PORT_ArenaZAlloc(arena, valueLen); - } else { - buf = (char *)PORT_ZAlloc(valueLen); - } - if (buf) { - SECStatus rv = escapeAndQuote(buf, valueLen, (char *)avaValue->data, - avaValue->len, NULL); - if (rv != SECSuccess) { - if (!arena) - PORT_Free(buf); - buf = NULL; - } - } - SECITEM_FreeItem(avaValue, PR_TRUE); - return buf; -} - -/* RDNs are sorted from most general to most specific. - * This code returns the FIRST one found, the most general one found. - */ -static char * -CERT_GetNameElement(PRArenaPool *arena, CERTName *name, int wantedTag) -{ - CERTRDN** rdns = name->rdns; - CERTRDN* rdn; - CERTAVA* ava = NULL; - - while (rdns && (rdn = *rdns++) != 0) { - CERTAVA** avas = rdn->avas; - while (avas && (ava = *avas++) != 0) { - int tag = CERT_GetAVATag(ava); - if ( tag == wantedTag ) { - avas = NULL; - rdns = NULL; /* break out of all loops */ - } - } - } - return ava ? avaToString(arena, ava) : NULL; -} - -/* RDNs are sorted from most general to most specific. - * This code returns the LAST one found, the most specific one found. - * This is particularly appropriate for Common Name. See RFC 2818. - */ -static char * -CERT_GetLastNameElement(PRArenaPool *arena, CERTName *name, int wantedTag) -{ - CERTRDN** rdns = name->rdns; - CERTRDN* rdn; - CERTAVA* lastAva = NULL; - - while (rdns && (rdn = *rdns++) != 0) { - CERTAVA** avas = rdn->avas; - CERTAVA* ava; - while (avas && (ava = *avas++) != 0) { - int tag = CERT_GetAVATag(ava); - if ( tag == wantedTag ) { - lastAva = ava; - } - } - } - return lastAva ? avaToString(arena, lastAva) : NULL; -} - -char * -CERT_GetCertificateEmailAddress(CERTCertificate *cert) -{ - char *rawEmailAddr = NULL; - SECItem subAltName; - SECStatus rv; - CERTGeneralName *nameList = NULL; - CERTGeneralName *current; - PRArenaPool *arena = NULL; - int i; - - subAltName.data = NULL; - - rawEmailAddr = CERT_GetNameElement(cert->arena, &(cert->subject), - SEC_OID_PKCS9_EMAIL_ADDRESS); - if ( rawEmailAddr == NULL ) { - rawEmailAddr = CERT_GetNameElement(cert->arena, &(cert->subject), - SEC_OID_RFC1274_MAIL); - } - if ( rawEmailAddr == NULL) { - - rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, - &subAltName); - if (rv != SECSuccess) { - goto finish; - } - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (!arena) { - goto finish; - } - nameList = current = CERT_DecodeAltNameExtension(arena, &subAltName); - if (!nameList ) { - goto finish; - } - if (nameList != NULL) { - do { - if (current->type == certDirectoryName) { - rawEmailAddr = CERT_GetNameElement(cert->arena, - &(current->name.directoryName), - SEC_OID_PKCS9_EMAIL_ADDRESS); - if ( rawEmailAddr == NULL ) { - rawEmailAddr = CERT_GetNameElement(cert->arena, - &(current->name.directoryName), SEC_OID_RFC1274_MAIL); - } - } else if (current->type == certRFC822Name) { - rawEmailAddr = (char*)PORT_ArenaZAlloc(cert->arena, - current->name.other.len + 1); - if (!rawEmailAddr) { - goto finish; - } - PORT_Memcpy(rawEmailAddr, current->name.other.data, - current->name.other.len); - rawEmailAddr[current->name.other.len] = '\0'; - } - if (rawEmailAddr) { - break; - } - current = CERT_GetNextGeneralName(current); - } while (current != nameList); - } - } - if (rawEmailAddr) { - for (i = 0; i <= (int) PORT_Strlen(rawEmailAddr); i++) { - rawEmailAddr[i] = tolower(rawEmailAddr[i]); - } - } - -finish: - - /* Don't free nameList, it's part of the arena. */ - - if (arena) { - PORT_FreeArena(arena, PR_FALSE); - } - - if ( subAltName.data ) { - SECITEM_FreeItem(&subAltName, PR_FALSE); - } - - return(rawEmailAddr); -} - -static char * -appendStringToBuf(char *dest, char *src, PRUint32 *pRemaining) -{ - PRUint32 len; - if (dest && src && src[0] && *pRemaining > (len = PL_strlen(src))) { - PRUint32 i; - for (i = 0; i < len; ++i) - dest[i] = tolower(src[i]); - dest[len] = 0; - dest += len + 1; - *pRemaining -= len + 1; - } - return dest; -} - -#undef NEEDS_HEX_ESCAPE -#define NEEDS_HEX_ESCAPE(c) (c < 0x20) - -static char * -appendItemToBuf(char *dest, SECItem *src, PRUint32 *pRemaining) -{ - if (dest && src && src->data && src->len && src->data[0]) { - PRUint32 len = src->len; - PRUint32 i; - PRUint32 reqLen = len + 1; - /* are there any embedded control characters ? */ - for (i = 0; i < len; i++) { - if (NEEDS_HEX_ESCAPE(src->data[i])) - reqLen += 2; - } - if (*pRemaining > reqLen) { - for (i = 0; i < len; ++i) { - PRUint8 c = src->data[i]; - if (NEEDS_HEX_ESCAPE(c)) { - *dest++ = C_BACKSLASH; - *dest++ = hexChars[ (c >> 4) & 0x0f ]; - *dest++ = hexChars[ c & 0x0f ]; - } else { - *dest++ = tolower(c); - } - } - *dest++ = '\0'; - *pRemaining -= reqLen; - } - } - return dest; -} - -/* Returns a pointer to an environment-like string, a series of -** null-terminated strings, terminated by a zero-length string. -** This function is intended to be internal to NSS. -*/ -char * -cert_GetCertificateEmailAddresses(CERTCertificate *cert) -{ - char * rawEmailAddr = NULL; - char * addrBuf = NULL; - char * pBuf = NULL; - PRArenaPool * tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - PRUint32 maxLen = 0; - PRInt32 finalLen = 0; - SECStatus rv; - SECItem subAltName; - - if (!tmpArena) - return addrBuf; - - subAltName.data = NULL; - maxLen = cert->derCert.len; - PORT_Assert(maxLen); - if (!maxLen) - maxLen = 2000; /* a guess, should never happen */ - - pBuf = addrBuf = (char *)PORT_ArenaZAlloc(tmpArena, maxLen + 1); - if (!addrBuf) - goto loser; - - rawEmailAddr = CERT_GetNameElement(tmpArena, &cert->subject, - SEC_OID_PKCS9_EMAIL_ADDRESS); - pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen); - - rawEmailAddr = CERT_GetNameElement(tmpArena, &cert->subject, - SEC_OID_RFC1274_MAIL); - pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen); - - rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, - &subAltName); - if (rv == SECSuccess && subAltName.data) { - CERTGeneralName *nameList = NULL; - - if (!!(nameList = CERT_DecodeAltNameExtension(tmpArena, &subAltName))) { - CERTGeneralName *current = nameList; - do { - if (current->type == certDirectoryName) { - rawEmailAddr = CERT_GetNameElement(tmpArena, - ¤t->name.directoryName, - SEC_OID_PKCS9_EMAIL_ADDRESS); - pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen); - - rawEmailAddr = CERT_GetNameElement(tmpArena, - ¤t->name.directoryName, - SEC_OID_RFC1274_MAIL); - pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen); - } else if (current->type == certRFC822Name) { - pBuf = appendItemToBuf(pBuf, ¤t->name.other, &maxLen); - } - current = CERT_GetNextGeneralName(current); - } while (current != nameList); - } - SECITEM_FreeItem(&subAltName, PR_FALSE); - /* Don't free nameList, it's part of the tmpArena. */ - } - /* now copy superstring to cert's arena */ - finalLen = (pBuf - addrBuf) + 1; - pBuf = NULL; - if (finalLen > 1) { - pBuf = PORT_ArenaAlloc(cert->arena, finalLen); - if (pBuf) { - PORT_Memcpy(pBuf, addrBuf, finalLen); - } - } -loser: - if (tmpArena) - PORT_FreeArena(tmpArena, PR_FALSE); - - return pBuf; -} - -/* returns pointer to storage in cert's arena. Storage remains valid -** as long as cert's reference count doesn't go to zero. -** Caller should strdup or otherwise copy. -*/ -const char * /* const so caller won't muck with it. */ -CERT_GetFirstEmailAddress(CERTCertificate * cert) -{ - if (cert && cert->emailAddr && cert->emailAddr[0]) - return (const char *)cert->emailAddr; - return NULL; -} - -/* returns pointer to storage in cert's arena. Storage remains valid -** as long as cert's reference count doesn't go to zero. -** Caller should strdup or otherwise copy. -*/ -const char * /* const so caller won't muck with it. */ -CERT_GetNextEmailAddress(CERTCertificate * cert, const char * prev) -{ - if (cert && prev && prev[0]) { - PRUint32 len = PL_strlen(prev); - prev += len + 1; - if (prev && prev[0]) - return prev; - } - return NULL; -} - -/* This is seriously bogus, now that certs store their email addresses in -** subject Alternative Name extensions. -** Returns a string allocated by PORT_StrDup, which the caller must free. -*/ -char * -CERT_GetCertEmailAddress(CERTName *name) -{ - char *rawEmailAddr; - char *emailAddr; - - - rawEmailAddr = CERT_GetNameElement(NULL, name, SEC_OID_PKCS9_EMAIL_ADDRESS); - if ( rawEmailAddr == NULL ) { - rawEmailAddr = CERT_GetNameElement(NULL, name, SEC_OID_RFC1274_MAIL); - } - emailAddr = CERT_FixupEmailAddr(rawEmailAddr); - if ( rawEmailAddr ) { - PORT_Free(rawEmailAddr); - } - return(emailAddr); -} - -/* The return value must be freed with PORT_Free. */ -char * -CERT_GetCommonName(CERTName *name) -{ - return(CERT_GetLastNameElement(NULL, name, SEC_OID_AVA_COMMON_NAME)); -} - -char * -CERT_GetCountryName(CERTName *name) -{ - return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_COUNTRY_NAME)); -} - -char * -CERT_GetLocalityName(CERTName *name) -{ - return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_LOCALITY)); -} - -char * -CERT_GetStateName(CERTName *name) -{ - return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_STATE_OR_PROVINCE)); -} - -char * -CERT_GetOrgName(CERTName *name) -{ - return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_ORGANIZATION_NAME)); -} - -char * -CERT_GetDomainComponentName(CERTName *name) -{ - return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_DC)); -} - -char * -CERT_GetOrgUnitName(CERTName *name) -{ - return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME)); -} - -char * -CERT_GetDnQualifier(CERTName *name) -{ - return(CERT_GetNameElement(NULL, name, SEC_OID_AVA_DN_QUALIFIER)); -} - -char * -CERT_GetCertUid(CERTName *name) -{ - return(CERT_GetNameElement(NULL, name, SEC_OID_RFC1274_UID)); -} - |