Index: mozilla/security/nss/cmd/lib/secutil.c =================================================================== RCS file: mozilla/security/nss/cmd/lib/secutil.c,v retrieving revision 1.93 diff -p -u -r1.93 secutil.c --- mozilla/security/nss/cmd/lib/secutil.c 16 Feb 2009 03:47:16 -0000 1.93 +++ mozilla/security/nss/cmd/lib/secutil.c 14 Mar 2009 04:47:14 -0000 @@ -998,7 +998,6 @@ secu_PrintRawString(FILE *out, SECItem * SECU_Indent(out, level); column = level*INDENT_MULT; } - fprintf(out, "\""); column++; for (i = 0; i < si->len; i++) { unsigned char val = si->data[i]; @@ -1010,7 +1009,6 @@ secu_PrintRawString(FILE *out, SECItem * fprintf(out,"%c", printable[val]); column++; } - fprintf(out, "\""); column++; if (column != level*INDENT_MULT || column > 76) { secu_Newline(out); } Index: mozilla/security/nss/lib/certdb/alg1485.c =================================================================== RCS file: /cvsroot/mozilla/security/nss/lib/certdb/alg1485.c,v retrieving revision 1.31 diff -p -u -r1.31 alg1485.c --- mozilla/security/nss/lib/certdb/alg1485.c 22 Feb 2009 12:27:33 -0000 1.31 +++ mozilla/security/nss/lib/certdb/alg1485.c 14 Mar 2009 04:47:15 -0000 @@ -111,6 +111,28 @@ static const NameToKind name2kinds[] = { { 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' @@ -140,6 +162,17 @@ static const NameToKind name2kinds[] = { ((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) { @@ -222,11 +255,12 @@ scanTag(char **pbp, char *endptr, char * return SECSuccess; } -static SECStatus +/* Returns the number of bytes in the value. 0 means failure. */ +static int scanVal(char **pbp, char *endptr, char *valBuf, int valBufSize) { char *bp, *valBufp; - int vallen; + int vallen = 0; PRBool isQuoted; PORT_Assert(valBufSize > 0); @@ -235,7 +269,7 @@ scanVal(char **pbp, char *endptr, char * skipSpace(pbp, endptr); if(*pbp == endptr) { /* nothing left */ - return SECFailure; + return 0; } bp = *pbp; @@ -250,7 +284,6 @@ scanVal(char **pbp, char *endptr, char * } valBufp = valBuf; - vallen = 0; while (bp < endptr) { char c = *bp; if (c == C_BACKSLASH) { @@ -259,7 +292,12 @@ scanVal(char **pbp, char *endptr, char * if (bp >= endptr) { /* escape charater must appear with paired char */ *pbp = bp; - return SECFailure; + 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. */ @@ -274,27 +312,28 @@ scanVal(char **pbp, char *endptr, char * vallen++; if (vallen >= valBufSize) { *pbp = bp; - return SECFailure; + return 0; } - *valBufp++ = *bp++; + *valBufp++ = c; + bp++; } - /* stip trailing spaces from unquoted values */ + /* strip trailing spaces from unquoted values */ if (!isQuoted) { - if (valBufp > valBuf) { - valBufp--; - while ((valBufp > valBuf) && OPTIONAL_SPACE(*valBufp)) { - valBufp--; - } - valBufp++; + 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 SECFailure; + return 0; } /* skip over the quote and skip optional space */ bp++; @@ -303,37 +342,12 @@ scanVal(char **pbp, char *endptr, char * *pbp = bp; - if (valBufp == valBuf) { - /* empty value -- not allowed */ - return SECFailure; - } - /* null-terminate valBuf -- guaranteed at least one space left */ - *valBufp++ = 0; + *valBufp = 0; - return SECSuccess; + return vallen; } -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 -}; - /* Caller must set error code upon failure */ static SECStatus hexToBin(PLArenaPool *pool, SECItem * destItem, const char * src, int len) @@ -379,13 +393,14 @@ ParseRFC1485AVA(PRArenaPool *arena, char SECOidTag kind = SEC_OID_UNKNOWN; SECStatus rv = SECFailure; SECItem derOid = { 0, NULL, 0 }; + SECItem derVal = { 0, NULL, 0}; char tagBuf[32]; char valBuf[384]; PORT_Assert(arena); - if (scanTag(pbp, endptr, tagBuf, sizeof(tagBuf)) == SECFailure || - scanVal(pbp, endptr, valBuf, sizeof(valBuf)) == SECFailure) { + if (SECSuccess != scanTag(pbp, endptr, tagBuf, sizeof tagBuf) || + !(valLen = scanVal(pbp, endptr, valBuf, sizeof valBuf))) { goto loser; } @@ -423,16 +438,13 @@ ParseRFC1485AVA(PRArenaPool *arena, char /* Is this a hex encoding of a DER attribute value ? */ if ('#' == valBuf[0]) { /* convert attribute value from hex to binary */ - SECItem derVal = { 0, NULL, 0}; - valLen = PORT_Strlen(valBuf+1); - rv = hexToBin(arena, &derVal, valBuf + 1, valLen); + 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; - valLen = PORT_Strlen(valBuf); if (kind == SEC_OID_AVA_COUNTRY_NAME && valLen != 2) goto loser; if (vt == SEC_ASN1_PRINTABLE_STRING && @@ -446,7 +458,9 @@ ParseRFC1485AVA(PRArenaPool *arena, char vt = SEC_ASN1_UTF8_STRING; } - a = CERT_CreateAVA(arena, kind, vt, (char *)valBuf); + derVal.data = valBuf; + derVal.len = valLen; + a = CERT_CreateAVAFromSECItem(arena, kind, vt, &derVal); } return a; @@ -580,10 +594,26 @@ AppendStr(stringBuf *bufp, char *str) 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 preceeding 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, PRBool *pNeedsQuoting) +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; @@ -591,70 +621,91 @@ cert_RFC1485_GetRequiredLen(const char * for (i = 0; i < srclen; i++) { char c = src[i]; reqLen++; - if (!needsQuoting && (SPECIAL_CHAR(c) || - (OPTIONAL_SPACE(c) && OPTIONAL_SPACE(lastC)))) { - /* entirety will need quoting */ - needsQuoting = PR_TRUE; - } - if (c == C_DOUBLE_QUOTE || c == C_BACKSLASH) { - /* this char will need escaping */ + 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 && + if (!needsQuoting && srclen > 0 && mode == minimalEscapeAndQuote && (OPTIONAL_SPACE(src[srclen-1]) || OPTIONAL_SPACE(src[0]))) { needsQuoting = PR_TRUE; } if (needsQuoting) reqLen += 2; - if (pNeedsQuoting) - *pNeedsQuoting = needsQuoting; - + if (pEQMode && mode == minimalEscapeAndQuote && !needsQuoting) + *pEQMode = minimalEscape; return reqLen; } -SECStatus -CERT_RFC1485_EscapeAndQuote(char *dst, int dstlen, char *src, int srclen) +static const char hexChars[16] = { "0123456789abcdef" }; + +static SECStatus +escapeAndQuote(char *dst, int dstlen, char *src, int srclen, EQMode *pEQMode) { int i, reqLen=0; - char *d = dst; - PRBool needsQuoting = PR_FALSE; + EQMode mode = pEQMode ? *pEQMode : minimalEscape; /* space for terminal null */ - reqLen = cert_RFC1485_GetRequiredLen(src, srclen, &needsQuoting) + 1; + reqLen = cert_RFC1485_GetRequiredLen(src, srclen, &mode) + 1; if (reqLen > dstlen) { PORT_SetError(SEC_ERROR_OUTPUT_LEN); return SECFailure; } - d = dst; - if (needsQuoting) *d++ = C_DOUBLE_QUOTE; + if (mode == minimalEscapeAndQuote) + *dst++ = C_DOUBLE_QUOTE; for (i = 0; i < srclen; i++) { char c = src[i]; - if (c == C_DOUBLE_QUOTE || c == C_BACKSLASH) { - /* escape it */ - *d++ = C_BACKSLASH; + 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; + } + *dst++ = c; } - *d++ = c; } - if (needsQuoting) *d++ = C_DOUBLE_QUOTE; - *d++ = 0; + 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 *end; - PRUint8 *d; - PRUint8 *e; - char *a = NULL; - char *b; + 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 */ @@ -663,75 +714,113 @@ CERT_GetOidString(const SECItem *oid) return NULL; } - /* d will point to the next sequence of bytes to decode */ - d = (PRUint8 *)oid->data; - /* end points to one past the legitimate data */ - end = &d[ oid->len ]; + /* 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( (*d == 0x80) && (2 == oid->len) ) { + if ((*first == 0x80) && (2 == oid->len)) { /* Funky encoding. The second byte is the number */ - a = PR_smprintf("%lu", (PRUint32)d[1]); - if( (char *)NULL == a ) { + rvString = PR_smprintf("%lu", (PRUint32)first[1]); + if (!rvString) { PORT_SetError(SEC_ERROR_NO_MEMORY); - return (char *)NULL; } - return a; + return rvString; } - for( ; d < end; d = &e[1] ) { + for (; first < stop; first = last + 1) { + unsigned int bytesBeforeLast; - for( e = d; e < end; e++ ) { - if( 0 == (*e & 0x80) ) { + for (last = first; last < stop; last++) { + if (0 == (*last & 0x80)) { break; } } - - if( ((e-d) > 4) || (((e-d) == 4) && (*d & 0x70)) ) { - /* More than a 32-bit number */ - } else { + bytesBeforeLast = (unsigned int)(last - first); + if (bytesBeforeLast <= 3U) { /* 0-28 bit number */ PRUint32 n = 0; - - switch( e-d ) { - case 4: - n |= ((PRUint32)(e[-4] & 0x0f)) << 28; - case 3: - n |= ((PRUint32)(e[-3] & 0x7f)) << 21; - case 2: - n |= ((PRUint32)(e[-2] & 0x7f)) << 14; - case 1: - n |= ((PRUint32)(e[-1] & 0x7f)) << 7; - case 0: - n |= ((PRUint32)(e[-0] & 0x7f)) ; + 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]; /* most significant bit is zero. */ + break; } - if( (char *)NULL == a ) { + if (!rvString) { /* This is the first number.. decompose it */ PRUint32 one = PR_MIN(n/40, 2); /* never > 2 */ - PRUint32 two = n - one * 40; + PRUint32 two = n - (one * 40); - a = PR_smprintf("OID.%lu.%lu", one, two); - if( (char *)NULL == a ) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - return (char *)NULL; - } + rvString = PR_smprintf("OID.%lu.%lu", one, two); } else { - b = PR_smprintf("%s.%lu", a, n); - if( (char *)NULL == b ) { - PR_smprintf_free(a); - PORT_SetError(SEC_ERROR_NO_MEMORY); - return (char *)NULL; - } + 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); + n |= last[0]; /* most significant bit is zero. */ + break; + } + + if (!rvString) { + /* This is the first number.. decompose it */ + PRUint64 one = PR_MIN(n/40, 2); /* never > 2 */ + PRUint64 two = n - (one * 40); - PR_smprintf_free(a); - a = b; + 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); } } - } - return a; + 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 */ @@ -826,6 +915,7 @@ AppendAVA(stringBuf *bufp, CERTAVA *ava, SECStatus rv; unsigned int len; int nameLen, valueLen; + EQMode mode = minimalEscapeAndQuote; NameToKind n2k = { NULL, 32767, SEC_OID_UNKNOWN, SEC_ASN1_DS }; char tmpBuf[384]; @@ -907,7 +997,8 @@ AppendAVA(stringBuf *bufp, CERTAVA *ava, nameLen = strlen(tagName); valueLen = (useHex ? avaValue->len : - cert_RFC1485_GetRequiredLen(avaValue->data, avaValue->len, NULL)); + cert_RFC1485_GetRequiredLen(avaValue->data, avaValue->len, + &mode)); len = nameLen + valueLen + 2; /* Add 2 for '=' and trailing NUL */ if (len <= sizeof(tmpBuf)) { @@ -934,8 +1025,8 @@ AppendAVA(stringBuf *bufp, CERTAVA *ava, encodedAVA[nameLen + avaValue->len] = '\0'; rv = SECSuccess; } else - rv = CERT_RFC1485_EscapeAndQuote(encodedAVA + nameLen, len - nameLen, - (char *)avaValue->data, avaValue->len); + rv = escapeAndQuote(encodedAVA + nameLen, len - nameLen, + (char *)avaValue->data, avaValue->len, &mode); SECITEM_FreeItem(avaValue, PR_TRUE); if (rv == SECSuccess) rv = AppendStr(bufp, encodedAVA); @@ -990,7 +1081,7 @@ CERT_NameToAsciiInvertible(CERTName *nam first = PR_FALSE; } - /* Add in tag type plus value into buf */ + /* Add in tag type plus value into strBuf */ rv = AppendAVA(&strBuf, ava, strict); if (rv) goto loser; newRDN = PR_FALSE; @@ -1044,44 +1135,58 @@ loser: 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(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; - CERTRDN *rdn; - char *buf = 0; - - rdns = name->rdns; + CERTRDN** rdns = name->rdns; + CERTRDN* rdn; + CERTAVA* ava = 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 ) { - SECItem *decodeItem = CERT_DecodeAVAValue(&ava->value); - if(!decodeItem) { - return NULL; - } - if (arena) { - buf = (char *)PORT_ArenaZAlloc(arena,decodeItem->len + 1); - } else { - buf = (char *)PORT_ZAlloc(decodeItem->len + 1); - } - if ( buf ) { - PORT_Memcpy(buf, decodeItem->data, decodeItem->len); - buf[decodeItem->len] = 0; - } - SECITEM_FreeItem(decodeItem, PR_TRUE); - goto done; + avas = NULL; + rdns = NULL; /* break out of all loops */ } } } - - done: - return buf; + return ava ? avaToString(arena, ava) : NULL; } /* RDNs are sorted from most general to most specific. @@ -1091,12 +1196,10 @@ CERT_GetNameElement(PRArenaPool *arena, static char * CERT_GetLastNameElement(PRArenaPool *arena, CERTName *name, int wantedTag) { - CERTRDN** rdns; - CERTRDN *rdn; - CERTAVA * lastAva = NULL; - char *buf = 0; + CERTRDN** rdns = name->rdns; + CERTRDN* rdn; + CERTAVA* lastAva = NULL; - rdns = name->rdns; while (rdns && (rdn = *rdns++) != 0) { CERTAVA** avas = rdn->avas; CERTAVA* ava; @@ -1107,24 +1210,7 @@ CERT_GetLastNameElement(PRArenaPool *are } } } - - if (lastAva) { - SECItem *decodeItem = CERT_DecodeAVAValue(&lastAva->value); - if(!decodeItem) { - return NULL; - } - if (arena) { - buf = (char *)PORT_ArenaZAlloc(arena,decodeItem->len + 1); - } else { - buf = (char *)PORT_ZAlloc(decodeItem->len + 1); - } - if ( buf ) { - PORT_Memcpy(buf, decodeItem->data, decodeItem->len); - buf[decodeItem->len] = 0; - } - SECITEM_FreeItem(decodeItem, PR_TRUE); - } - return buf; + return lastAva ? avaToString(arena, lastAva) : NULL; } char * Index: mozilla/security/nss/lib/certdb/certi.h =================================================================== RCS file: /cvsroot/mozilla/security/nss/lib/certdb/certi.h,v retrieving revision 1.27 diff -p -u -r1.27 certi.h --- mozilla/security/nss/lib/certdb/certi.h 31 Oct 2008 23:02:36 -0000 1.27 +++ mozilla/security/nss/lib/certdb/certi.h 14 Mar 2009 04:47:15 -0000 @@ -249,6 +249,10 @@ extern int cert_AVAOidTagToMaxLen(SECOid extern CERTAVA * CERT_CreateAVAFromRaw(PRArenaPool *pool, const SECItem * OID, const SECItem * value); +/* Make an AVA from binary input specified by SECItem */ +extern CERTAVA * CERT_CreateAVAFromSECItem(PRArenaPool *arena, SECOidTag kind, + int valueType, SECItem *value); + /* * get a DPCache object for the given issuer subject and dp * Automatically creates the cache object if it doesn't exist yet. Index: mozilla/security/lib/certdb/secname.c =================================================================== RCS file: /cvsroot/mozilla/security/nss/lib/certdb/secname.c,v retrieving revision 1.24 diff -p -u -r1.24 secname.c --- mozilla/security/nss/lib/certdb/secname.c 6 Jun 2008 01:15:18 -0000 1.24 +++ mozilla/security/nss/lib/certdb/secname.c 14 Mar 2009 04:47:15 -0000 @@ -149,31 +149,30 @@ SetupAVAType(PRArenaPool *arena, SECOidT } static SECStatus -SetupAVAValue(PRArenaPool *arena, int valueType, char *value, SECItem *it, - unsigned maxLen) +SetupAVAValue(PRArenaPool *arena, int valueType, const SECItem *in, + SECItem *out, unsigned maxLen) { + PRUint8 *value, *cp, *ucs4Val; unsigned valueLen, valueLenLen, total; unsigned ucs4Len = 0, ucs4MaxLen; - unsigned char *cp, *ucs4Val; + value = in->data; + valueLen = in->len; switch (valueType) { case SEC_ASN1_PRINTABLE_STRING: case SEC_ASN1_IA5_STRING: case SEC_ASN1_T61_STRING: case SEC_ASN1_UTF8_STRING: /* no conversion required */ - valueLen = PORT_Strlen(value); break; case SEC_ASN1_UNIVERSAL_STRING: - valueLen = PORT_Strlen(value); ucs4MaxLen = valueLen * 6; - ucs4Val = (unsigned char *)PORT_ArenaZAlloc(arena, ucs4MaxLen); - if(!ucs4Val || !PORT_UCS4_UTF8Conversion(PR_TRUE, - (unsigned char *)value, valueLen, + ucs4Val = (PRUint8 *)PORT_ArenaZAlloc(arena, ucs4MaxLen); + if(!ucs4Val || !PORT_UCS4_UTF8Conversion(PR_TRUE, value, valueLen, ucs4Val, ucs4MaxLen, &ucs4Len)) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } - value = (char *)ucs4Val; + value = ucs4Val; valueLen = ucs4Len; maxLen *= 4; break; @@ -189,12 +188,13 @@ SetupAVAValue(PRArenaPool *arena, int va valueLenLen = DER_LengthLength(valueLen); total = 1 + valueLenLen + valueLen; - it->data = cp = (unsigned char*) PORT_ArenaAlloc(arena, total); + cp = (PRUint8*)PORT_ArenaAlloc(arena, total); if (!cp) { return SECFailure; } - it->len = total; - cp = (unsigned char*) DER_StoreHeader(cp, valueType, valueLen); + out->data = cp; + out->len = total; + cp = (PRUint8 *)DER_StoreHeader(cp, valueType, valueLen); PORT_Memcpy(cp, value, valueLen); return SECSuccess; } @@ -220,7 +220,8 @@ CERT_CreateAVAFromRaw(PRArenaPool *pool, } CERTAVA * -CERT_CreateAVA(PRArenaPool *arena, SECOidTag kind, int valueType, char *value) +CERT_CreateAVAFromSECItem(PRArenaPool *arena, SECOidTag kind, int valueType, + SECItem *value) { CERTAVA *ava; int rv; @@ -231,18 +232,29 @@ CERT_CreateAVA(PRArenaPool *arena, SECOi rv = SetupAVAType(arena, kind, &ava->type, &maxLen); if (rv) { /* Illegal AVA type */ - return 0; + return NULL; } rv = SetupAVAValue(arena, valueType, value, &ava->value, maxLen); if (rv) { /* Illegal value type */ - return 0; + return NULL; } } return ava; } CERTAVA * +CERT_CreateAVA(PRArenaPool *arena, SECOidTag kind, int valueType, char *value) +{ + SECItem item = { siBuffer, NULL, 0 }; + + item.data = (PRUint8 *)value; + item.len = PORT_Strlen(value); + + return CERT_CreateAVAFromSECItem(arena, kind, valueType, &item); +} + +CERTAVA * CERT_CopyAVA(PRArenaPool *arena, CERTAVA *from) { CERTAVA *ava; Index: mozilla/security/nss/lib/certdb/alg1485.c =================================================================== RCS file: /cvsroot/mozilla/security/nss/lib/certdb/alg1485.c,v retrieving revision 1.32 diff -p -u -r1.32 alg1485.c --- mozilla/security/nss/lib/certdb/alg1485.c 17 Mar 2009 07:30:10 -0000 1.32 +++ mozilla/security/nss/lib/certdb/alg1485.c 18 Mar 2009 20:54:26 -0000 @@ -675,7 +675,6 @@ escapeAndQuote(char *dst, int dstlen, ch } else { if (NEEDS_ESCAPE(c) || (SPECIAL_CHAR(c) && mode == fullEscape)) { *dst++ = C_BACKSLASH; - *dst++ = c; } *dst++ = c; } Index: mozilla/security/nss/lib/certdb/alg1485.c =================================================================== RCS file: /cvsroot/mozilla/security/nss/lib/certdb/alg1485.c,v retrieving revision 1.33 diff -p -u -5 -r1.33 alg1485.c --- mozilla/security/nss/lib/certdb/alg1485.c 18 Mar 2009 23:14:45 -0000 1.33 +++ mozilla/security/nss/lib/certdb/alg1485.c 11 Apr 2009 20:02:35 -0000 @@ -755,13 +755,15 @@ CERT_GetOidString(const SECItem *oid) switch (bytesBeforeLast) { CASE(3, 0x7f); CASE(2, 0x7f); CASE(1, 0x7f); - case 0: n |= last[0]; /* most significant bit is zero. */ + CGET(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); @@ -783,13 +785,15 @@ CERT_GetOidString(const SECItem *oid) CASE(5, 0x7f); CASE(4, 0x7f); CGET(3, 0x7f); CGET(2, 0x7f); CGET(1, 0x7f); - n |= last[0]; /* most significant bit is zero. */ + 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); Index: mozilla/security/nss/lib/certdb/alg1485.c =================================================================== RCS file: /cvsroot/mozilla/security/nss/lib/certdb/alg1485.c,v retrieving revision 1.35 diff -p -u -r1.35 alg1485.c --- mozilla/security/nss/lib/certdb/alg1485.c 12 Apr 2009 04:34:00 -0000 1.35 +++ mozilla/security/nss/lib/certdb/alg1485.c 12 Apr 2009 05:38:39 -0000 @@ -757,7 +757,7 @@ CERT_GetOidString(const SECItem *oid) CASE(3, 0x7f); CASE(2, 0x7f); CASE(1, 0x7f); - CGET(0, 0x7f); + case 0: n |= last[0] & 0x7f; break; } if (last[0] & 0x80) Index: mozilla/security/nss/lib/certdb/cert.h =================================================================== RCS file: /cvsroot/mozilla/security/nss/lib/certdb/cert.h,v retrieving revision 1.75 diff -p -u -r1.75 cert.h --- mozilla/security/nss/lib/certdb/cert.h 21 Nov 2008 21:02:38 -0000 1.75 +++ mozilla/security/nss/lib/certdb/cert.h 19 Mar 2009 14:39:57 -0000 @@ -174,6 +174,17 @@ extern char *CERT_FormatName (CERTName * */ extern char *CERT_Hexify (SECItem *i, int do_colon); +/* +** Converts DER string (with explicit length) into zString, if destination +** buffer is big enough to receive it. Does quoting and/or escaping as +** specified in RFC 1485. Input string must be single or multi-byte DER +** character set, (ASCII, UTF8, or ISO 8851-x) not a wide character set. +** Returns SECSuccess or SECFailure with error code set. If output buffer +** is too small, sets error code SEC_ERROR_OUTPUT_LEN. +*/ +extern SECStatus +CERT_RFC1485_EscapeAndQuote(char *dst, int dstlen, char *src, int srclen); + /****************************************************************************** * * Certificate handling operations Index: mozilla/security/nss/lib/certdb/certdb.c =================================================================== RCS file: /cvsroot/mozilla/security/nss/lib/certdb/certdb.c,v retrieving revision 1.98 diff -p -u -r1.98 certdb.c --- mozilla/security/nss/lib/certdb/certdb.c 12 Mar 2009 08:53:51 -0000 1.98 +++ mozilla/security/nss/lib/certdb/certdb.c 19 Mar 2009 14:39:57 -0000 @@ -1552,15 +1552,18 @@ cert_VerifySubjectAltName(CERTCertificat ** so must copy it. */ int cnLen = current->name.other.len; - if (cnLen + 1 > cnBufLen) { - cnBufLen = cnLen + 1; + rv = CERT_RFC1485_EscapeAndQuote(cn, cnBufLen, + current->name.other.data, cnLen); + if (rv != SECSuccess && PORT_GetError == SEC_ERROR_OUTPUT_LEN) { + cnBufLen = cnLen * 3 + 3; /* big enough for worst case */ cn = (char *)PORT_ArenaAlloc(arena, cnBufLen); if (!cn) goto fail; + rv = CERT_RFC1485_EscapeAndQuote(cn, cnBufLen, + current->name.other.data, cnLen); } - PORT_Memcpy(cn, current->name.other.data, cnLen); - cn[cnLen] = 0; - rv = cert_TestHostName(cn ,hn); + if (rv == SECSuccess) + rv = cert_TestHostName(cn ,hn); if (rv == SECSuccess) goto finish; }