summaryrefslogtreecommitdiff
path: root/security/nss/lib/certdb
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/certdb')
-rw-r--r--security/nss/lib/certdb/.cvsignore1
-rw-r--r--security/nss/lib/certdb/Makefile76
-rw-r--r--security/nss/lib/certdb/alg1485.c1248
-rw-r--r--security/nss/lib/certdb/cert.h1493
-rw-r--r--security/nss/lib/certdb/certdb.c2918
-rw-r--r--security/nss/lib/certdb/certdb.h159
-rw-r--r--security/nss/lib/certdb/certi.h213
-rw-r--r--security/nss/lib/certdb/certt.h853
-rw-r--r--security/nss/lib/certdb/certv3.c406
-rw-r--r--security/nss/lib/certdb/certxutl.c482
-rw-r--r--security/nss/lib/certdb/certxutl.h79
-rw-r--r--security/nss/lib/certdb/config.mk43
-rw-r--r--security/nss/lib/certdb/crl.c1950
-rw-r--r--security/nss/lib/certdb/genname.c1610
-rw-r--r--security/nss/lib/certdb/genname.h125
-rw-r--r--security/nss/lib/certdb/manifest.mn68
-rw-r--r--security/nss/lib/certdb/polcyxtn.c565
-rw-r--r--security/nss/lib/certdb/secname.c653
-rw-r--r--security/nss/lib/certdb/stanpcertdb.c978
-rw-r--r--security/nss/lib/certdb/xauthkid.c155
-rw-r--r--security/nss/lib/certdb/xbsconst.c168
-rw-r--r--security/nss/lib/certdb/xconst.c257
-rw-r--r--security/nss/lib/certdb/xconst.h82
23 files changed, 14582 insertions, 0 deletions
diff --git a/security/nss/lib/certdb/.cvsignore b/security/nss/lib/certdb/.cvsignore
new file mode 100644
index 000000000..ec60123e5
--- /dev/null
+++ b/security/nss/lib/certdb/.cvsignore
@@ -0,0 +1 @@
+nscertinit.c
diff --git a/security/nss/lib/certdb/Makefile b/security/nss/lib/certdb/Makefile
new file mode 100644
index 000000000..12eff17ab
--- /dev/null
+++ b/security/nss/lib/certdb/Makefile
@@ -0,0 +1,76 @@
+#! gmake
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Netscape security libraries.
+#
+# The Initial Developer of the Original Code is Netscape
+# Communications Corporation. Portions created by Netscape are
+# Copyright (C) 1994-2000 Netscape Communications Corporation. All
+# Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the
+# terms of the GNU General Public License Version 2 or later (the
+# "GPL"), in which case the provisions of the GPL are applicable
+# instead of those above. If you wish to allow use of your
+# version of this file only under the terms of the GPL and not to
+# allow others to use your version of this file under the MPL,
+# indicate your decision by deleting the provisions above and
+# replace them with the notice and other provisions required by
+# the GPL. If you do not delete the provisions above, a recipient
+# may use your version of this file under either the MPL or the
+# GPL.
+#
+
+#######################################################################
+# (1) Include initial platform-independent assignments (MANDATORY). #
+#######################################################################
+
+include manifest.mn
+
+#######################################################################
+# (2) Include "global" configuration information. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/config.mk
+
+#######################################################################
+# (3) Include "component" configuration information. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (4) Include "local" platform-dependent assignments (OPTIONAL). #
+#######################################################################
+
+include config.mk
+
+#######################################################################
+# (5) Execute "global" rules. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/rules.mk
+
+#######################################################################
+# (6) Execute "component" rules. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (7) Execute "local" rules. (OPTIONAL). #
+#######################################################################
+
+export:: private_export
+
diff --git a/security/nss/lib/certdb/alg1485.c b/security/nss/lib/certdb/alg1485.c
new file mode 100644
index 000000000..e414f4eb4
--- /dev/null
+++ b/security/nss/lib/certdb/alg1485.c
@@ -0,0 +1,1248 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+#include "prprf.h"
+#include "cert.h"
+#include "xconst.h"
+#include "genname.h"
+#include "secitem.h"
+#include "secerr.h"
+
+struct NameToKind {
+ char *name;
+ SECOidTag kind;
+};
+
+static struct NameToKind name2kinds[] = {
+ { "CN", SEC_OID_AVA_COMMON_NAME, },
+ { "ST", SEC_OID_AVA_STATE_OR_PROVINCE, },
+ { "OU", SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME, },
+ { "DC", SEC_OID_AVA_DC, },
+ { "C", SEC_OID_AVA_COUNTRY_NAME, },
+ { "O", SEC_OID_AVA_ORGANIZATION_NAME, },
+ { "L", SEC_OID_AVA_LOCALITY, },
+ { "dnQualifier", SEC_OID_AVA_DN_QUALIFIER, },
+ { "E", SEC_OID_PKCS9_EMAIL_ADDRESS, },
+ { "UID", SEC_OID_RFC1274_UID, },
+ { "MAIL", SEC_OID_RFC1274_MAIL, },
+ { 0, SEC_OID_UNKNOWN },
+};
+
+#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))
+
+
+
+
+
+
+
+#if 0
+/*
+** Find the start and end of a <string>. Strings can be wrapped in double
+** quotes to protect special characters.
+*/
+static int BracketThing(char **startp, char *end, char *result)
+{
+ char *start = *startp;
+ char c;
+
+ /* Skip leading white space */
+ while (start < end) {
+ c = *start++;
+ if (!OPTIONAL_SPACE(c)) {
+ start--;
+ break;
+ }
+ }
+ if (start == end) return 0;
+
+ switch (*start) {
+ case '#':
+ /* Process hex thing */
+ start++;
+ *startp = start;
+ while (start < end) {
+ c = *start++;
+ if (((c >= '0') && (c <= '9')) ||
+ ((c >= 'a') && (c <= 'f')) ||
+ ((c >= 'A') && (c <= 'F'))) {
+ continue;
+ }
+ break;
+ }
+ rv = IS_HEX;
+ break;
+
+ case C_DOUBLE_QUOTE:
+ start++;
+ *startp = start;
+ while (start < end) {
+ c = *start++;
+ if (c == C_DOUBLE_QUOTE) {
+ break;
+ }
+ *result++ = c;
+ }
+ rv = IS_STRING;
+ break;
+
+ default:
+ while (start < end) {
+ c = *start++;
+ if (SPECIAL_CHAR(c)) {
+ start--;
+ break;
+ }
+ *result++ = c;
+ }
+ rv = IS_STRING;
+ break;
+ }
+
+ /* Terminate result string */
+ *result = 0;
+ return start;
+}
+
+static char *BracketSomething(char **startp, char* end, int spacesOK)
+{
+ char *start = *startp;
+ char c;
+ int stopAtDQ;
+
+ /* Skip leading white space */
+ while (start < end) {
+ c = *start;
+ if (!OPTIONAL_SPACE(c)) {
+ break;
+ }
+ start++;
+ }
+ if (start == end) return 0;
+ stopAtDQ = 0;
+ if (*start == C_DOUBLE_QUOTE) {
+ stopAtDQ = 1;
+ }
+
+ /*
+ ** Find the end of the something. The something is terminated most of
+ ** the time by a space. However, if spacesOK is true then it is
+ ** terminated by a special character only.
+ */
+ *startp = start;
+ while (start < end) {
+ c = *start;
+ if (stopAtDQ) {
+ if (c == C_DOUBLE_QUOTE) {
+ *start = ' ';
+ break;
+ }
+ } else {
+ if (SPECIAL_CHAR(c)) {
+ break;
+ }
+ if (!spacesOK && OPTIONAL_SPACE(c)) {
+ break;
+ }
+ }
+ start++;
+ }
+ return start;
+}
+#endif
+
+#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) == '?'))
+
+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 PRBool
+Is7Bit(unsigned char *data, unsigned len)
+{
+ unsigned char ch, *end;
+
+ end = data + len;
+ while (data < end) {
+ ch = *data++;
+ if ((ch & 0x80)) {
+ return PR_FALSE;
+ }
+ }
+ return PR_TRUE;
+}
+
+static void
+skipSpace(char **pbp, char *endptr)
+{
+ char *bp = *pbp;
+ while (bp < endptr && OPTIONAL_SPACE(*bp)) {
+ bp++;
+ }
+ *pbp = bp;
+}
+
+static SECStatus
+scanTag(char **pbp, char *endptr, char *tagBuf, int tagBufSize)
+{
+ char *bp, *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;
+}
+
+static SECStatus
+scanVal(char **pbp, char *endptr, char *valBuf, int valBufSize)
+{
+ char *bp, *valBufp;
+ int vallen;
+ PRBool isQuoted;
+
+ PORT_Assert(valBufSize > 0);
+
+ /* skip optional leading space */
+ skipSpace(pbp, endptr);
+ if(*pbp == endptr) {
+ /* nothing left */
+ return SECFailure;
+ }
+
+ bp = *pbp;
+
+ /* quoted? */
+ if (*bp == C_DOUBLE_QUOTE) {
+ isQuoted = PR_TRUE;
+ /* skip over it */
+ bp++;
+ } else {
+ isQuoted = PR_FALSE;
+ }
+
+ valBufp = valBuf;
+ vallen = 0;
+ 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 SECFailure;
+ }
+ } 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 SECFailure;
+ }
+ *valBufp++ = *bp++;
+ }
+
+ /* stip trailing spaces from unquoted values */
+ if (!isQuoted) {
+ if (valBufp > valBuf) {
+ valBufp--;
+ while ((valBufp > valBuf) && OPTIONAL_SPACE(*valBufp)) {
+ valBufp--;
+ }
+ valBufp++;
+ }
+ }
+
+ if (isQuoted) {
+ /* insist that we stopped on a double quote */
+ if (*bp != C_DOUBLE_QUOTE) {
+ *pbp = bp;
+ return SECFailure;
+ }
+ /* skip over the quote and skip optional space */
+ bp++;
+ skipSpace(&bp, endptr);
+ }
+
+ *pbp = bp;
+
+ if (valBufp == valBuf) {
+ /* empty value -- not allowed */
+ return SECFailure;
+ }
+
+ /* null-terminate valBuf -- guaranteed at least one space left */
+ *valBufp++ = 0;
+
+ return SECSuccess;
+}
+
+CERTAVA *
+CERT_ParseRFC1485AVA(PRArenaPool *arena, char **pbp, char *endptr,
+ PRBool singleAVA)
+{
+ CERTAVA *a;
+ struct NameToKind *n2k;
+ int vt;
+ int valLen;
+ char *bp;
+
+ char tagBuf[32];
+ char valBuf[384];
+
+ if (scanTag(pbp, endptr, tagBuf, sizeof(tagBuf)) == SECFailure ||
+ scanVal(pbp, endptr, valBuf, sizeof(valBuf)) == SECFailure) {
+ PORT_SetError(SEC_ERROR_INVALID_AVA);
+ return 0;
+ }
+
+ /* insist that if we haven't finished we've stopped on a separator */
+ bp = *pbp;
+ if (bp < endptr) {
+ if (singleAVA || (*bp != ',' && *bp != ';')) {
+ PORT_SetError(SEC_ERROR_INVALID_AVA);
+ *pbp = bp;
+ return 0;
+ }
+ /* ok, skip over separator */
+ bp++;
+ }
+ *pbp = bp;
+
+ for (n2k = name2kinds; n2k->name; n2k++) {
+ if (PORT_Strcasecmp(n2k->name, tagBuf) == 0) {
+ valLen = PORT_Strlen(valBuf);
+ if (n2k->kind == SEC_OID_AVA_COUNTRY_NAME) {
+ vt = SEC_ASN1_PRINTABLE_STRING;
+ if (valLen != 2) {
+ PORT_SetError(SEC_ERROR_INVALID_AVA);
+ return 0;
+ }
+ if (!IsPrintable((unsigned char*) valBuf, 2)) {
+ PORT_SetError(SEC_ERROR_INVALID_AVA);
+ return 0;
+ }
+ } else if ((n2k->kind == SEC_OID_PKCS9_EMAIL_ADDRESS) ||
+ (n2k->kind == SEC_OID_RFC1274_MAIL)) {
+ vt = SEC_ASN1_IA5_STRING;
+ } else {
+ /* Hack -- for rationale see X.520 DirectoryString defn */
+ if (IsPrintable((unsigned char*)valBuf, valLen)) {
+ vt = SEC_ASN1_PRINTABLE_STRING;
+ } else if (Is7Bit((unsigned char *)valBuf, valLen)) {
+ vt = SEC_ASN1_T61_STRING;
+ } else {
+ vt = SEC_ASN1_UNIVERSAL_STRING;
+ }
+ }
+ a = CERT_CreateAVA(arena, n2k->kind, vt, (char *) valBuf);
+ return a;
+ }
+ }
+ /* matched no kind -- invalid tag */
+ PORT_SetError(SEC_ERROR_INVALID_AVA);
+ return 0;
+}
+
+static CERTName *
+ParseRFC1485Name(char *buf, int len)
+{
+ SECStatus rv;
+ CERTName *name;
+ char *bp, *e;
+ CERTAVA *ava;
+ CERTRDN *rdn;
+
+ name = CERT_CreateName(NULL);
+ if (name == NULL) {
+ return NULL;
+ }
+
+ e = buf + len;
+ bp = buf;
+ while (bp < e) {
+ ava = CERT_ParseRFC1485AVA(name->arena, &bp, e, PR_FALSE);
+ if (ava == 0) goto loser;
+ rdn = CERT_CreateRDN(name->arena, ava, 0);
+ if (rdn == 0) goto loser;
+ rv = CERT_AddRDN(name, rdn);
+ if (rv) goto loser;
+ 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(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
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+
+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 = 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;
+}
+
+SECStatus
+CERT_RFC1485_EscapeAndQuote(char *dst, int dstlen, char *src, int srclen)
+{
+ int i, reqLen=0;
+ char *d = dst;
+ PRBool needsQuoting = PR_FALSE;
+
+ /* need to make an initial pass to determine if quoting is needed */
+ for (i = 0; i < srclen; i++) {
+ char c = src[i];
+ reqLen++;
+ if (SPECIAL_CHAR(c)) {
+ /* entirety will need quoting */
+ needsQuoting = PR_TRUE;
+ }
+ if (c == C_DOUBLE_QUOTE || c == C_BACKSLASH) {
+ /* this char will need escaping */
+ reqLen++;
+ }
+ }
+ /* if it begins or ends in optional space it needs quoting */
+ if (srclen > 0 &&
+ (OPTIONAL_SPACE(src[srclen-1]) || OPTIONAL_SPACE(src[0]))) {
+ needsQuoting = PR_TRUE;
+ }
+
+ if (needsQuoting) reqLen += 2;
+
+ /* space for terminal null */
+ reqLen++;
+
+ if (reqLen > dstlen) {
+ PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+ return SECFailure;
+ }
+
+ d = dst;
+ if (needsQuoting) *d++ = 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;
+ }
+ *d++ = c;
+ }
+ if (needsQuoting) *d++ = C_DOUBLE_QUOTE;
+ *d++ = 0;
+ return SECSuccess;
+}
+
+/* convert an OID to dotted-decimal representation */
+static char *
+get_oid_string
+(
+ SECItem *oid
+)
+{
+ PRUint8 *end;
+ PRUint8 *d;
+ PRUint8 *e;
+ char *a;
+ char *b;
+
+ a = (char *)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 ];
+
+ /*
+ * Check for our pseudo-encoded single-digit OIDs
+ */
+ if( (*d == 0x80) && (2 == oid->len) ) {
+ /* Funky encoding. The second byte is the number */
+ a = PR_smprintf("%lu", (PRUint32)d[1]);
+ if( (char *)NULL == a ) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return (char *)NULL;
+ }
+ return a;
+ }
+
+ for( ; d < end; d = &e[1] ) {
+
+ for( e = d; e < end; e++ ) {
+ if( 0 == (*e & 0x80) ) {
+ break;
+ }
+ }
+
+ if( ((e-d) > 4) || (((e-d) == 4) && (*d & 0x70)) ) {
+ /* More than a 32-bit number */
+ } else {
+ 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)) ;
+ }
+
+ if( (char *)NULL == a ) {
+ /* This is the first number.. decompose it */
+ PRUint32 one = PR_MIN(n/40, 2); /* never > 2 */
+ PRUint32 two = n - one * 40;
+
+ a = PR_smprintf("%lu.%lu", one, two);
+ if( (char *)NULL == a ) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return (char *)NULL;
+ }
+ } 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;
+ }
+
+ PR_smprintf_free(a);
+ a = b;
+ }
+ }
+ }
+
+ return a;
+}
+
+/* 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;
+}
+
+static SECStatus
+AppendAVA(stringBuf *bufp, CERTAVA *ava)
+{
+ char *tagName;
+ char tmpBuf[384];
+ unsigned len, maxLen;
+ int tag;
+ SECStatus rv;
+ SECItem *avaValue = NULL;
+ char *unknownTag = NULL;
+
+ tag = CERT_GetAVATag(ava);
+ switch (tag) {
+ case SEC_OID_AVA_COUNTRY_NAME:
+ tagName = "C";
+ maxLen = 2;
+ break;
+ case SEC_OID_AVA_ORGANIZATION_NAME:
+ tagName = "O";
+ maxLen = 64;
+ break;
+ case SEC_OID_AVA_COMMON_NAME:
+ tagName = "CN";
+ maxLen = 64;
+ break;
+ case SEC_OID_AVA_LOCALITY:
+ tagName = "L";
+ maxLen = 128;
+ break;
+ case SEC_OID_AVA_STATE_OR_PROVINCE:
+ tagName = "ST";
+ maxLen = 128;
+ break;
+ case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME:
+ tagName = "OU";
+ maxLen = 64;
+ break;
+ case SEC_OID_AVA_DC:
+ tagName = "DC";
+ maxLen = 128;
+ break;
+ case SEC_OID_AVA_DN_QUALIFIER:
+ tagName = "dnQualifier";
+ maxLen = 0x7fff;
+ break;
+ case SEC_OID_PKCS9_EMAIL_ADDRESS:
+ tagName = "E";
+ maxLen = 128;
+ break;
+ case SEC_OID_RFC1274_UID:
+ tagName = "UID";
+ maxLen = 256;
+ break;
+ case SEC_OID_RFC1274_MAIL:
+ tagName = "MAIL";
+ maxLen = 256;
+ break;
+ default:
+ /* handle unknown attribute types per RFC 2253 */
+ tagName = unknownTag = get_oid_string(&ava->type);
+ maxLen = 256;
+ break;
+ }
+
+ avaValue = CERT_DecodeAVAValue(&ava->value);
+ if(!avaValue) {
+ /* the attribute value is not recognized, get the hex value */
+ avaValue = get_hex_string(&ava->value);
+ if(!avaValue) {
+ if (unknownTag) PR_smprintf_free(unknownTag);
+ return SECFailure;
+ }
+ }
+
+ /* Check value length */
+ if (avaValue->len > maxLen) {
+ if (unknownTag) PR_smprintf_free(unknownTag);
+ PORT_SetError(SEC_ERROR_INVALID_AVA);
+ return SECFailure;
+ }
+
+ len = PORT_Strlen(tagName);
+ if (len+1 > sizeof(tmpBuf)) {
+ if (unknownTag) PR_smprintf_free(unknownTag);
+ PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+ return SECFailure;
+ }
+ PORT_Memcpy(tmpBuf, tagName, len);
+ if (unknownTag) PR_smprintf_free(unknownTag);
+ tmpBuf[len++] = '=';
+
+ /* escape and quote as necessary */
+ rv = CERT_RFC1485_EscapeAndQuote(tmpBuf+len, sizeof(tmpBuf)-len,
+ (char *)avaValue->data, avaValue->len);
+ SECITEM_FreeItem(avaValue, PR_TRUE);
+ if (rv) return SECFailure;
+
+ rv = AppendStr(bufp, tmpBuf);
+ return rv;
+}
+
+char *
+CERT_NameToAscii(CERTName *name)
+{
+ SECStatus rv;
+ CERTRDN** rdns;
+ CERTRDN** lastRdn;
+ CERTRDN** rdn;
+ CERTAVA** avas;
+ CERTAVA* ava;
+ 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--) {
+ avas = (*rdn)->avas;
+ while ((ava = *avas++) != NULL) {
+ /* Put in comma separator */
+ if (!first) {
+ rv = AppendStr(&strBuf, ", ");
+ if (rv) goto loser;
+ } else {
+ first = PR_FALSE;
+ }
+
+ /* Add in tag type plus value into buf */
+ rv = AppendAVA(&strBuf, ava);
+ if (rv) goto loser;
+ }
+ }
+ return strBuf.buffer;
+ loser:
+ if (strBuf.buffer) {
+ PORT_Free(strBuf.buffer);
+ }
+ return NULL;
+}
+
+/*
+ * 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 *
+CERT_GetNameElement(PRArenaPool *arena, CERTName *name, int wantedTag)
+{
+ CERTRDN** rdns;
+ CERTRDN *rdn;
+ CERTAVA** avas;
+ CERTAVA* ava;
+ char *buf = 0;
+ int tag;
+ SECItem *decodeItem = NULL;
+
+ rdns = name->rdns;
+ while ((rdn = *rdns++) != 0) {
+ avas = rdn->avas;
+ while ((ava = *avas++) != 0) {
+ tag = CERT_GetAVATag(ava);
+ if ( tag == wantedTag ) {
+ 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;
+ }
+ }
+ }
+
+ done:
+ return buf;
+}
+
+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_get_next_general_name(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;
+}
+
+static char *
+appendItemToBuf(char *dest, SECItem *src, PRUint32 *pRemaining)
+{
+ if (dest && src && src->data && src->len && src->data[0] &&
+ *pRemaining > src->len + 1 ) {
+ PRUint32 len = src->len;
+ PRUint32 i;
+ for (i = 0; i < len && src->data[i] ; ++i)
+ dest[i] = tolower(src->data[i]);
+ dest[len] = 0;
+ dest += len + 1;
+ *pRemaining -= len + 1;
+ }
+ 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,
+ &current->name.directoryName,
+ SEC_OID_PKCS9_EMAIL_ADDRESS);
+ pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
+
+ rawEmailAddr = CERT_GetNameElement(tmpArena,
+ &current->name.directoryName,
+ SEC_OID_RFC1274_MAIL);
+ pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
+ } else if (current->type == certRFC822Name) {
+ pBuf = appendItemToBuf(pBuf, &current->name.other, &maxLen);
+ }
+ current = cert_get_next_general_name(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 = 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);
+}
+
+char *
+CERT_GetCommonName(CERTName *name)
+{
+ return(CERT_GetNameElement(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));
+}
+
diff --git a/security/nss/lib/certdb/cert.h b/security/nss/lib/certdb/cert.h
new file mode 100644
index 000000000..1131b1633
--- /dev/null
+++ b/security/nss/lib/certdb/cert.h
@@ -0,0 +1,1493 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+ * cert.h - public data structures and prototypes for the certificate library
+ *
+ * $Id$
+ */
+
+#ifndef _CERT_H_
+#define _CERT_H_
+
+#include "plarena.h"
+#include "plhash.h"
+#include "prlong.h"
+#include "prlog.h"
+
+#include "seccomon.h"
+#include "secdert.h"
+#include "secoidt.h"
+#include "keyt.h"
+#include "certt.h"
+
+SEC_BEGIN_PROTOS
+
+/****************************************************************************
+ *
+ * RFC1485 ascii to/from X.? RelativeDistinguishedName (aka CERTName)
+ *
+ ****************************************************************************/
+
+/*
+** Convert an ascii RFC1485 encoded name into its CERTName equivalent.
+*/
+extern CERTName *CERT_AsciiToName(char *string);
+
+/*
+** Convert an CERTName into its RFC1485 encoded equivalent.
+*/
+extern char *CERT_NameToAscii(CERTName *name);
+
+extern CERTAVA *CERT_CopyAVA(PRArenaPool *arena, CERTAVA *src);
+
+/*
+** Examine an AVA and return the tag that refers to it. The AVA tags are
+** defined as SEC_OID_AVA*.
+*/
+extern SECOidTag CERT_GetAVATag(CERTAVA *ava);
+
+/*
+** Compare two AVA's, returning the difference between them.
+*/
+extern SECComparison CERT_CompareAVA(CERTAVA *a, CERTAVA *b);
+
+/*
+** Create an RDN (relative-distinguished-name). The argument list is a
+** NULL terminated list of AVA's.
+*/
+extern CERTRDN *CERT_CreateRDN(PRArenaPool *arena, CERTAVA *avas, ...);
+
+/*
+** Make a copy of "src" storing it in "dest".
+*/
+extern SECStatus CERT_CopyRDN(PRArenaPool *arena, CERTRDN *dest, CERTRDN *src);
+
+/*
+** Destory an RDN object.
+** "rdn" the RDN to destroy
+** "freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void CERT_DestroyRDN(CERTRDN *rdn, PRBool freeit);
+
+/*
+** Add an AVA to an RDN.
+** "rdn" the RDN to add to
+** "ava" the AVA to add
+*/
+extern SECStatus CERT_AddAVA(PRArenaPool *arena, CERTRDN *rdn, CERTAVA *ava);
+
+/*
+** Compare two RDN's, returning the difference between them.
+*/
+extern SECComparison CERT_CompareRDN(CERTRDN *a, CERTRDN *b);
+
+/*
+** Create an X.500 style name using a NULL terminated list of RDN's.
+*/
+extern CERTName *CERT_CreateName(CERTRDN *rdn, ...);
+
+/*
+** Make a copy of "src" storing it in "dest". Memory is allocated in
+** "dest" for each of the appropriate sub objects. Memory is not freed in
+** "dest" before allocation is done (use CERT_DestroyName(dest, PR_FALSE) to
+** do that).
+*/
+extern SECStatus CERT_CopyName(PRArenaPool *arena, CERTName *dest, CERTName *src);
+
+/*
+** Destroy a Name object.
+** "name" the CERTName to destroy
+** "freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void CERT_DestroyName(CERTName *name);
+
+/*
+** Add an RDN to a name.
+** "name" the name to add the RDN to
+** "rdn" the RDN to add to name
+*/
+extern SECStatus CERT_AddRDN(CERTName *name, CERTRDN *rdn);
+
+/*
+** Compare two names, returning the difference between them.
+*/
+extern SECComparison CERT_CompareName(CERTName *a, CERTName *b);
+
+/*
+** Convert a CERTName into something readable
+*/
+extern char *CERT_FormatName (CERTName *name);
+
+/*
+** Convert a der-encoded integer to a hex printable string form.
+** Perhaps this should be a SEC function but it's only used for certs.
+*/
+extern char *CERT_Hexify (SECItem *i, int do_colon);
+
+/******************************************************************************
+ *
+ * Certificate handling operations
+ *
+ *****************************************************************************/
+
+/*
+** Create a new validity object given two unix time values.
+** "notBefore" the time before which the validity is not valid
+** "notAfter" the time after which the validity is not valid
+*/
+extern CERTValidity *CERT_CreateValidity(int64 notBefore, int64 notAfter);
+
+/*
+** Destroy a validity object.
+** "v" the validity to destroy
+** "freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void CERT_DestroyValidity(CERTValidity *v);
+
+/*
+** Copy the "src" object to "dest". Memory is allocated in "dest" for
+** each of the appropriate sub-objects. Memory in "dest" is not freed
+** before memory is allocated (use CERT_DestroyValidity(v, PR_FALSE) to do
+** that).
+*/
+extern SECStatus CERT_CopyValidity
+ (PRArenaPool *arena, CERTValidity *dest, CERTValidity *src);
+
+/*
+** The cert lib considers a cert or CRL valid if the "notBefore" time is
+** in the not-too-distant future, e.g. within the next 24 hours. This
+** prevents freshly issued certificates from being considered invalid
+** because the local system's time zone is incorrectly set.
+** The amount of "pending slop time" is adjustable by the application.
+** Units of SlopTime are seconds. Default is 86400 (24 hours).
+** Negative SlopTime values are not allowed.
+*/
+PRInt32 CERT_GetSlopTime(void);
+
+SECStatus CERT_SetSlopTime(PRInt32 slop);
+
+/*
+** Create a new certificate object. The result must be wrapped with an
+** CERTSignedData to create a signed certificate.
+** "serialNumber" the serial number
+** "issuer" the name of the certificate issuer
+** "validity" the validity period of the certificate
+** "req" the certificate request that prompted the certificate issuance
+*/
+extern CERTCertificate *
+CERT_CreateCertificate (unsigned long serialNumber, CERTName *issuer,
+ CERTValidity *validity, CERTCertificateRequest *req);
+
+/*
+** Destroy a certificate object
+** "cert" the certificate to destroy
+** NOTE: certificate's are reference counted. This call decrements the
+** reference count, and if the result is zero, then the object is destroyed
+** and optionally freed.
+*/
+extern void CERT_DestroyCertificate(CERTCertificate *cert);
+
+/*
+** Make a shallow copy of a certificate "c". Just increments the
+** reference count on "c".
+*/
+extern CERTCertificate *CERT_DupCertificate(CERTCertificate *c);
+
+/*
+** Create a new certificate request. This result must be wrapped with an
+** CERTSignedData to create a signed certificate request.
+** "name" the subject name (who the certificate request is from)
+** "spki" describes/defines the public key the certificate is for
+** "attributes" if non-zero, some optional attribute data
+*/
+extern CERTCertificateRequest *
+CERT_CreateCertificateRequest (CERTName *name, CERTSubjectPublicKeyInfo *spki,
+ SECItem **attributes);
+
+/*
+** Destroy a certificate-request object
+** "r" the certificate-request to destroy
+** "freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void CERT_DestroyCertificateRequest(CERTCertificateRequest *r);
+
+/*
+** Extract a public key object from a SubjectPublicKeyInfo
+*/
+extern SECKEYPublicKey *CERT_ExtractPublicKey(CERTCertificate *cert);
+
+/*
+ * used to get a public key with Key Material ID. Only used for fortezza V1
+ * certificates.
+ */
+extern SECKEYPublicKey *CERT_KMIDPublicKey(CERTCertificate *cert);
+
+
+/*
+** Retrieve the Key Type associated with the cert we're dealing with
+*/
+
+extern KeyType CERT_GetCertKeyType (CERTSubjectPublicKeyInfo *spki);
+
+/*
+** Initialize the certificate database. This is called to create
+** the initial list of certificates in the database.
+*/
+extern SECStatus CERT_InitCertDB(CERTCertDBHandle *handle);
+
+extern int CERT_GetDBContentVersion(CERTCertDBHandle *handle);
+
+/*
+** Default certificate database routines
+*/
+extern void CERT_SetDefaultCertDB(CERTCertDBHandle *handle);
+
+extern CERTCertDBHandle *CERT_GetDefaultCertDB(void);
+
+extern CERTCertList *CERT_GetCertChainFromCert(CERTCertificate *cert,
+ int64 time,
+ SECCertUsage usage);
+extern CERTCertificate *
+CERT_NewTempCertificate (CERTCertDBHandle *handle, SECItem *derCert,
+ char *nickname, PRBool isperm, PRBool copyDER);
+
+
+/******************************************************************************
+ *
+ * X.500 Name handling operations
+ *
+ *****************************************************************************/
+
+/*
+** Create an AVA (attribute-value-assertion)
+** "arena" the memory arena to alloc from
+** "kind" is one of SEC_OID_AVA_*
+** "valueType" is one of DER_PRINTABLE_STRING, DER_IA5_STRING, or
+** DER_T61_STRING
+** "value" is the null terminated string containing the value
+*/
+extern CERTAVA *CERT_CreateAVA
+ (PRArenaPool *arena, SECOidTag kind, int valueType, char *value);
+
+/*
+** Extract the Distinguished Name from a DER encoded certificate
+** "derCert" is the DER encoded certificate
+** "derName" is the SECItem that the name is returned in
+*/
+extern SECStatus CERT_NameFromDERCert(SECItem *derCert, SECItem *derName);
+
+/*
+** Extract the Issuers Distinguished Name from a DER encoded certificate
+** "derCert" is the DER encoded certificate
+** "derName" is the SECItem that the name is returned in
+*/
+extern SECStatus CERT_IssuerNameFromDERCert(SECItem *derCert,
+ SECItem *derName);
+
+
+
+/*
+** Generate a database search key for a certificate, based on the
+** issuer and serial number.
+** "arena" the memory arena to alloc from
+** "derCert" the DER encoded certificate
+** "key" the returned key
+*/
+extern SECStatus CERT_KeyFromDERCert(PRArenaPool *arena, SECItem *derCert, SECItem *key);
+
+extern SECStatus CERT_KeyFromIssuerAndSN(PRArenaPool *arena, SECItem *issuer,
+ SECItem *sn, SECItem *key);
+
+extern SECStatus CERT_SerialNumberFromDERCert(SECItem *derCert,
+ SECItem *derName);
+
+
+/*
+** Generate a database search key for a crl, based on the
+** issuer.
+** "arena" the memory arena to alloc from
+** "derCrl" the DER encoded crl
+** "key" the returned key
+*/
+extern SECStatus CERT_KeyFromDERCrl(PRArenaPool *arena, SECItem *derCrl, SECItem *key);
+
+/*
+** Open the certificate database. Use callback to get name of database.
+*/
+extern SECStatus CERT_OpenCertDB(CERTCertDBHandle *handle, PRBool readOnly,
+ CERTDBNameFunc namecb, void *cbarg);
+
+/* Open the certificate database. Use given filename for database. */
+extern SECStatus CERT_OpenCertDBFilename(CERTCertDBHandle *handle,
+ char *certdbname, PRBool readOnly);
+
+/*
+** Open and initialize a cert database that is entirely in memory. This
+** can be used when the permanent database can not be opened or created.
+*/
+extern SECStatus CERT_OpenVolatileCertDB(CERTCertDBHandle *handle);
+
+/*
+** Check the hostname to make sure that it matches the shexp that
+** is given in the common name of the certificate.
+*/
+extern SECStatus CERT_VerifyCertName(CERTCertificate *cert, const char *hostname);
+
+/*
+** Add a domain name to the list of names that the user has explicitly
+** allowed (despite cert name mismatches) for use with a server cert.
+*/
+extern SECStatus CERT_AddOKDomainName(CERTCertificate *cert, const char *hostname);
+
+/*
+** Decode a DER encoded certificate into an CERTCertificate structure
+** "derSignedCert" is the DER encoded signed certificate
+** "copyDER" is true if the DER should be copied, false if the
+** existing copy should be referenced
+** "nickname" is the nickname to use in the database. If it is NULL
+** then a temporary nickname is generated.
+*/
+extern CERTCertificate *
+CERT_DecodeDERCertificate (SECItem *derSignedCert, PRBool copyDER, char *nickname);
+/*
+** Decode a DER encoded CRL/KRL into an CERTSignedCrl structure
+** "derSignedCrl" is the DER encoded signed crl/krl.
+** "type" is this a CRL or KRL.
+*/
+#define SEC_CRL_TYPE 1
+#define SEC_KRL_TYPE 0
+
+extern CERTSignedCrl *
+CERT_DecodeDERCrl (PRArenaPool *arena, SECItem *derSignedCrl,int type);
+
+/*
+ * same as CERT_DecodeDERCrl, plus allow options to be passed in
+ */
+
+extern CERTSignedCrl *
+CERT_DecodeDERCrlWithFlags(PRArenaPool *narena, SECItem *derSignedCrl,
+ int type, PRInt32 options);
+
+/* CRL options to pass */
+
+#define CRL_DECODE_DEFAULT_OPTIONS 0x00000000
+
+/* when CRL_DECODE_DONT_COPY_DER is set, the DER is not copied . The
+ application must then keep derSignedCrl until it destroys the
+ CRL . Ideally, it should allocate derSignedCrl in an arena
+ and pass that arena in as the first argument to
+ CERT_DecodeDERCrlWithFlags */
+
+#define CRL_DECODE_DONT_COPY_DER 0x00000001
+#define CRL_DECODE_SKIP_ENTRIES 0x00000002
+#define CRL_DECODE_KEEP_BAD_CRL 0x00000004
+
+/* complete the decoding of a partially decoded CRL, ie. decode the
+ entries. Note that entries is an optional field in a CRL, so the
+ "entries" pointer in CERTCrlStr may still be NULL even after
+ function returns SECSuccess */
+
+extern SECStatus CERT_CompleteCRLDecodeEntries(CERTSignedCrl* crl);
+
+/* Validate CRL then import it to the dbase. If there is already a CRL with the
+ * same CA in the dbase, it will be replaced if derCRL is more up to date.
+ * If the process successes, a CRL will be returned. Otherwise, a NULL will
+ * be returned. The caller should call PORT_GetError() for the exactly error
+ * code.
+ */
+extern CERTSignedCrl *
+CERT_ImportCRL (CERTCertDBHandle *handle, SECItem *derCRL, char *url,
+ int type, void * wincx);
+
+extern void CERT_DestroyCrl (CERTSignedCrl *crl);
+
+/* this is a hint to flush the CRL cache. crlKey is the DER subject of
+ the issuer (CA). */
+void CERT_CRLCacheRefreshIssuer(CERTCertDBHandle* dbhandle, SECItem* crlKey);
+
+/*
+** Decode a certificate and put it into the temporary certificate database
+*/
+extern CERTCertificate *
+CERT_DecodeCertificate (SECItem *derCert, char *nickname,PRBool copyDER);
+
+/*
+** Find a certificate in the database
+** "key" is the database key to look for
+*/
+extern CERTCertificate *CERT_FindCertByKey(CERTCertDBHandle *handle, SECItem *key);
+
+/*
+** Find a certificate in the database by name
+** "name" is the distinguished name to look up
+*/
+extern CERTCertificate *
+CERT_FindCertByName (CERTCertDBHandle *handle, SECItem *name);
+
+/*
+** Find a certificate in the database by name
+** "name" is the distinguished name to look up (in ascii)
+*/
+extern CERTCertificate *
+CERT_FindCertByNameString (CERTCertDBHandle *handle, char *name);
+
+/*
+** Find a certificate in the database by name and keyid
+** "name" is the distinguished name to look up
+** "keyID" is the value of the subjectKeyID to match
+*/
+extern CERTCertificate *
+CERT_FindCertByKeyID (CERTCertDBHandle *handle, SECItem *name, SECItem *keyID);
+
+/*
+** Generate a certificate key from the issuer and serialnumber, then look it
+** up in the database. Return the cert if found.
+** "issuerAndSN" is the issuer and serial number to look for
+*/
+extern CERTCertificate *
+CERT_FindCertByIssuerAndSN (CERTCertDBHandle *handle, CERTIssuerAndSN *issuerAndSN);
+
+/*
+** Find a certificate in the database by a subject key ID
+** "subjKeyID" is the subject Key ID to look for
+*/
+extern CERTCertificate *
+CERT_FindCertBySubjectKeyID (CERTCertDBHandle *handle, SECItem *subjKeyID);
+
+/*
+** Find a certificate in the database by a nickname
+** "nickname" is the ascii string nickname to look for
+*/
+extern CERTCertificate *
+CERT_FindCertByNickname (CERTCertDBHandle *handle, char *nickname);
+
+/*
+** Find a certificate in the database by a DER encoded certificate
+** "derCert" is the DER encoded certificate
+*/
+extern CERTCertificate *
+CERT_FindCertByDERCert(CERTCertDBHandle *handle, SECItem *derCert);
+
+/*
+** Find a certificate in the database by a email address
+** "emailAddr" is the email address to look up
+*/
+CERTCertificate *
+CERT_FindCertByEmailAddr(CERTCertDBHandle *handle, char *emailAddr);
+
+/*
+** Find a certificate in the database by a email address or nickname
+** "name" is the email address or nickname to look up
+*/
+CERTCertificate *
+CERT_FindCertByNicknameOrEmailAddr(CERTCertDBHandle *handle, char *name);
+
+/*
+** Find a certificate in the database by a digest of a subject public key
+** "spkDigest" is the digest to look up
+*/
+extern CERTCertificate *
+CERT_FindCertBySPKDigest(CERTCertDBHandle *handle, SECItem *spkDigest);
+
+/*
+ * Find the issuer of a cert
+ */
+CERTCertificate *
+CERT_FindCertIssuer(CERTCertificate *cert, int64 validTime, SECCertUsage usage);
+
+/*
+** Check the validity times of a certificate vs. time 't', allowing
+** some slop for broken clocks and stuff.
+** "cert" is the certificate to be checked
+** "t" is the time to check against
+** "allowOverride" if true then check to see if the invalidity has
+** been overridden by the user.
+*/
+extern SECCertTimeValidity CERT_CheckCertValidTimes(CERTCertificate *cert,
+ PRTime t,
+ PRBool allowOverride);
+
+/*
+** WARNING - this function is depricated, and will either go away or have
+** a new API in the near future.
+**
+** Check the validity times of a certificate vs. the current time, allowing
+** some slop for broken clocks and stuff.
+** "cert" is the certificate to be checked
+*/
+extern SECStatus CERT_CertTimesValid(CERTCertificate *cert);
+
+/*
+** Extract the validity times from a certificate
+** "c" is the certificate
+** "notBefore" is the start of the validity period
+** "notAfter" is the end of the validity period
+*/
+extern SECStatus
+CERT_GetCertTimes (CERTCertificate *c, PRTime *notBefore, PRTime *notAfter);
+
+/*
+** Extract the issuer and serial number from a certificate
+*/
+extern CERTIssuerAndSN *CERT_GetCertIssuerAndSN(PRArenaPool *,
+ CERTCertificate *);
+
+/*
+** verify the signature of a signed data object with a given certificate
+** "sd" the signed data object to be verified
+** "cert" the certificate to use to check the signature
+*/
+extern SECStatus CERT_VerifySignedData(CERTSignedData *sd,
+ CERTCertificate *cert,
+ int64 t,
+ void *wincx);
+/*
+** verify the signature of a signed data object with the given DER publickey
+*/
+extern SECStatus
+CERT_VerifySignedDataWithPublicKeyInfo(CERTSignedData *sd,
+ CERTSubjectPublicKeyInfo *pubKeyInfo,
+ void *wincx);
+
+/*
+** verify the signature of a signed data object with a SECKEYPublicKey.
+*/
+extern SECStatus
+CERT_VerifySignedDataWithPublicKey(CERTSignedData *sd,
+ SECKEYPublicKey *pubKey, void *wincx);
+
+/*
+** NEW FUNCTIONS with new bit-field-FIELD SECCertificateUsage - please use
+** verify a certificate by checking validity times against a certain time,
+** that we trust the issuer, and that the signature on the certificate is
+** valid.
+** "cert" the certificate to verify
+** "checkSig" only check signatures if true
+*/
+extern SECStatus
+CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert,
+ PRBool checkSig, SECCertificateUsage requiredUsages,
+ int64 t, void *wincx, CERTVerifyLog *log,
+ SECCertificateUsage* returnedUsages);
+
+/* same as above, but uses current time */
+extern SECStatus
+CERT_VerifyCertificateNow(CERTCertDBHandle *handle, CERTCertificate *cert,
+ PRBool checkSig, SECCertificateUsage requiredUsages,
+ void *wincx, SECCertificateUsage* returnedUsages);
+
+/*
+** Verify that a CA cert can certify some (unspecified) leaf cert for a given
+** purpose. This is used by UI code to help identify where a chain may be
+** broken and why. This takes identical parameters to CERT_VerifyCert
+*/
+extern SECStatus
+CERT_VerifyCACertForUsage(CERTCertDBHandle *handle, CERTCertificate *cert,
+ PRBool checkSig, SECCertUsage certUsage, int64 t,
+ void *wincx, CERTVerifyLog *log);
+
+/*
+** OLD OBSOLETE FUNCTIONS with enum SECCertUsage - DO NOT USE FOR NEW CODE
+** verify a certificate by checking validity times against a certain time,
+** that we trust the issuer, and that the signature on the certificate is
+** valid.
+** "cert" the certificate to verify
+** "checkSig" only check signatures if true
+*/
+extern SECStatus
+CERT_VerifyCert(CERTCertDBHandle *handle, CERTCertificate *cert,
+ PRBool checkSig, SECCertUsage certUsage, int64 t,
+ void *wincx, CERTVerifyLog *log);
+
+/* same as above, but uses current time */
+extern SECStatus
+CERT_VerifyCertNow(CERTCertDBHandle *handle, CERTCertificate *cert,
+ PRBool checkSig, SECCertUsage certUsage, void *wincx);
+
+SECStatus
+CERT_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert,
+ PRBool checkSig, SECCertUsage certUsage, int64 t,
+ void *wincx, CERTVerifyLog *log);
+
+/*
+** This must only be called on a cert that is known to have an issuer
+** with an invalid time
+*/
+extern CERTCertificate *
+CERT_FindExpiredIssuer (CERTCertDBHandle *handle, CERTCertificate *cert);
+
+/*
+** Read a base64 ascii encoded DER certificate and convert it to our
+** internal format.
+** "certstr" is a null-terminated string containing the certificate
+*/
+extern CERTCertificate *CERT_ConvertAndDecodeCertificate(char *certstr);
+
+/*
+** Read a certificate in some foreign format, and convert it to our
+** internal format.
+** "certbuf" is the buffer containing the certificate
+** "certlen" is the length of the buffer
+** NOTE - currently supports netscape base64 ascii encoded raw certs
+** and netscape binary DER typed files.
+*/
+extern CERTCertificate *CERT_DecodeCertFromPackage(char *certbuf, int certlen);
+
+extern SECStatus
+CERT_ImportCAChain (SECItem *certs, int numcerts, SECCertUsage certUsage);
+
+extern SECStatus
+CERT_ImportCAChainTrusted(SECItem *certs, int numcerts, SECCertUsage certUsage);
+
+/*
+** Read a certificate chain in some foreign format, and pass it to a
+** callback function.
+** "certbuf" is the buffer containing the certificate
+** "certlen" is the length of the buffer
+** "f" is the callback function
+** "arg" is the callback argument
+*/
+typedef SECStatus (PR_CALLBACK *CERTImportCertificateFunc)
+ (void *arg, SECItem **certs, int numcerts);
+
+extern SECStatus
+CERT_DecodeCertPackage(char *certbuf, int certlen, CERTImportCertificateFunc f,
+ void *arg);
+
+/*
+** Pretty print a certificate in HTML
+** "cert" is the certificate to print
+** "showImages" controls whether or not to use about:security URLs
+** for subject and issuer images. This should only be true
+** in the browser.
+*/
+extern char *CERT_HTMLCertInfo(CERTCertificate *cert, PRBool showImages,
+ PRBool showIssuer);
+
+/*
+** Returns the value of an AVA. This was a formerly static
+** function that has been exposed due to the need to decode
+** and convert unicode strings to UTF8.
+**
+** XXX This function resides in certhtml.c, should it be
+** moved elsewhere?
+*/
+extern SECItem *CERT_DecodeAVAValue(SECItem *derAVAValue);
+
+/*
+ * take a DER certificate and decode it into a certificate structure
+ */
+CERTCertificate *
+CERT_DecodeDERCertificate(SECItem *derSignedCert, PRBool copyDER,
+ char *nickname);
+
+
+
+/*
+** extract various element strings from a distinguished name.
+** "name" the distinguished name
+*/
+extern char *CERT_GetCommonName(CERTName *name);
+
+extern char *CERT_GetCertificateEmailAddress(CERTCertificate *cert);
+
+extern char *CERT_GetCertEmailAddress(CERTName *name);
+
+extern const char * CERT_GetFirstEmailAddress(CERTCertificate * cert);
+
+extern const char * CERT_GetNextEmailAddress(CERTCertificate * cert,
+ const char * prev);
+
+extern char *CERT_GetCommonName(CERTName *name);
+
+extern char *CERT_GetCountryName(CERTName *name);
+
+extern char *CERT_GetLocalityName(CERTName *name);
+
+extern char *CERT_GetStateName(CERTName *name);
+
+extern char *CERT_GetOrgName(CERTName *name);
+
+extern char *CERT_GetOrgUnitName(CERTName *name);
+
+extern char *CERT_GetDomainComponentName(CERTName *name);
+
+extern char *CERT_GetCertUid(CERTName *name);
+
+/* manipulate the trust parameters of a certificate */
+
+extern SECStatus CERT_GetCertTrust(CERTCertificate *cert, CERTCertTrust *trust);
+
+extern SECStatus
+CERT_ChangeCertTrust (CERTCertDBHandle *handle, CERTCertificate *cert,
+ CERTCertTrust *trust);
+
+extern SECStatus
+CERT_ChangeCertTrustByUsage(CERTCertDBHandle *certdb, CERTCertificate *cert,
+ SECCertUsage usage);
+
+/*************************************************************************
+ *
+ * manipulate the extensions of a certificate
+ *
+ ************************************************************************/
+
+/*
+** Set up a cert for adding X509v3 extensions. Returns an opaque handle
+** used by the next two routines.
+** "cert" is the certificate we are adding extensions to
+*/
+extern void *CERT_StartCertExtensions(CERTCertificate *cert);
+
+/*
+** Add an extension to a certificate.
+** "exthandle" is the handle returned by the previous function
+** "idtag" is the integer tag for the OID that should ID this extension
+** "value" is the value of the extension
+** "critical" is the critical extension flag
+** "copyData" is a flag indicating whether the value data should be
+** copied.
+*/
+extern SECStatus CERT_AddExtension (void *exthandle, int idtag,
+ SECItem *value, PRBool critical, PRBool copyData);
+
+extern SECStatus CERT_AddExtensionByOID (void *exthandle, SECItem *oid,
+ SECItem *value, PRBool critical, PRBool copyData);
+
+extern SECStatus CERT_EncodeAndAddExtension
+ (void *exthandle, int idtag, void *value, PRBool critical,
+ const SEC_ASN1Template *atemplate);
+
+extern SECStatus CERT_EncodeAndAddBitStrExtension
+ (void *exthandle, int idtag, SECItem *value, PRBool critical);
+
+
+extern SECStatus
+CERT_EncodeAltNameExtension(PRArenaPool *arena, CERTGeneralName *value, SECItem *encodedValue);
+
+
+/*
+** Finish adding cert extensions. Does final processing on extension
+** data, putting it in the right format, and freeing any temporary
+** storage.
+** "exthandle" is the handle used to add extensions to a certificate
+*/
+extern SECStatus CERT_FinishExtensions(void *exthandle);
+
+
+/* If the extension is found, return its criticality and value.
+** This allocate storage for the returning extension value.
+*/
+extern SECStatus CERT_GetExtenCriticality
+ (CERTCertExtension **extensions, int tag, PRBool *isCritical);
+
+extern void
+CERT_DestroyOidSequence(CERTOidSequence *oidSeq);
+
+/****************************************************************************
+ *
+ * DER encode and decode extension values
+ *
+ ****************************************************************************/
+
+/* Encode the value of the basicConstraint extension.
+** arena - where to allocate memory for the encoded value.
+** value - extension value to encode
+** encodedValue - output encoded value
+*/
+extern SECStatus CERT_EncodeBasicConstraintValue
+ (PRArenaPool *arena, CERTBasicConstraints *value, SECItem *encodedValue);
+
+/*
+** Encode the value of the authorityKeyIdentifier extension.
+*/
+extern SECStatus CERT_EncodeAuthKeyID
+ (PRArenaPool *arena, CERTAuthKeyID *value, SECItem *encodedValue);
+
+/*
+** Encode the value of the crlDistributionPoints extension.
+*/
+extern SECStatus CERT_EncodeCRLDistributionPoints
+ (PRArenaPool *arena, CERTCrlDistributionPoints *value,SECItem *derValue);
+
+/*
+** Decodes a DER encoded basicConstaint extension value into a readable format
+** value - decoded value
+** encodedValue - value to decoded
+*/
+extern SECStatus CERT_DecodeBasicConstraintValue
+ (CERTBasicConstraints *value, SECItem *encodedValue);
+
+/* Decodes a DER encoded authorityKeyIdentifier extension value into a
+** readable format.
+** arena - where to allocate memory for the decoded value
+** encodedValue - value to be decoded
+** Returns a CERTAuthKeyID structure which contains the decoded value
+*/
+extern CERTAuthKeyID *CERT_DecodeAuthKeyID
+ (PRArenaPool *arena, SECItem *encodedValue);
+
+
+/* Decodes a DER encoded crlDistributionPoints extension value into a
+** readable format.
+** arena - where to allocate memory for the decoded value
+** der - value to be decoded
+** Returns a CERTCrlDistributionPoints structure which contains the
+** decoded value
+*/
+extern CERTCrlDistributionPoints * CERT_DecodeCRLDistributionPoints
+ (PRArenaPool *arena, SECItem *der);
+
+/* Extract certain name type from a generalName */
+extern void *CERT_GetGeneralNameByType
+ (CERTGeneralName *genNames, CERTGeneralNameType type, PRBool derFormat);
+
+
+extern CERTOidSequence *
+CERT_DecodeOidSequence(SECItem *seqItem);
+
+
+
+
+/****************************************************************************
+ *
+ * Find extension values of a certificate
+ *
+ ***************************************************************************/
+
+extern SECStatus CERT_FindCertExtension
+ (CERTCertificate *cert, int tag, SECItem *value);
+
+extern SECStatus CERT_FindNSCertTypeExtension
+ (CERTCertificate *cert, SECItem *value);
+
+extern char * CERT_FindNSStringExtension (CERTCertificate *cert, int oidtag);
+
+extern SECStatus CERT_FindIssuerCertExtension
+ (CERTCertificate *cert, int tag, SECItem *value);
+
+extern SECStatus CERT_FindCertExtensionByOID
+ (CERTCertificate *cert, SECItem *oid, SECItem *value);
+
+extern char *CERT_FindCertURLExtension (CERTCertificate *cert, int tag,
+ int catag);
+
+/* Returns the decoded value of the authKeyID extension.
+** Note that this uses passed in the arena to allocate storage for the result
+*/
+extern CERTAuthKeyID * CERT_FindAuthKeyIDExten (PRArenaPool *arena,CERTCertificate *cert);
+
+/* Returns the decoded value of the basicConstraint extension.
+ */
+extern SECStatus CERT_FindBasicConstraintExten
+ (CERTCertificate *cert, CERTBasicConstraints *value);
+
+/* Returns the decoded value of the crlDistributionPoints extension.
+** Note that the arena in cert is used to allocate storage for the result
+*/
+extern CERTCrlDistributionPoints * CERT_FindCRLDistributionPoints
+ (CERTCertificate *cert);
+
+/* Returns value of the keyUsage extension. This uses PR_Alloc to allocate
+** buffer for the decoded value, The caller should free up the storage
+** allocated in value->data.
+*/
+extern SECStatus CERT_FindKeyUsageExtension (CERTCertificate *cert,
+ SECItem *value);
+
+/* Return the decoded value of the subjectKeyID extension. The caller should
+** free up the storage allocated in retItem->data.
+*/
+extern SECStatus CERT_FindSubjectKeyIDExtension (CERTCertificate *cert,
+ SECItem *retItem);
+
+/*
+** If cert is a v3 certificate, and a critical keyUsage extension is included,
+** then check the usage against the extension value. If a non-critical
+** keyUsage extension is included, this will return SECSuccess without
+** checking, since the extension is an advisory field, not a restriction.
+** If cert is not a v3 certificate, this will return SECSuccess.
+** cert - certificate
+** usage - one of the x.509 v3 the Key Usage Extension flags
+*/
+extern SECStatus CERT_CheckCertUsage (CERTCertificate *cert,
+ unsigned char usage);
+
+/****************************************************************************
+ *
+ * CRL v2 Extensions supported routines
+ *
+ ****************************************************************************/
+
+extern SECStatus CERT_FindCRLExtensionByOID
+ (CERTCrl *crl, SECItem *oid, SECItem *value);
+
+extern SECStatus CERT_FindCRLExtension
+ (CERTCrl *crl, int tag, SECItem *value);
+
+extern SECStatus
+ CERT_FindInvalidDateExten (CERTCrl *crl, int64 *value);
+
+extern void *CERT_StartCRLExtensions (CERTCrl *crl);
+
+extern CERTCertNicknames *CERT_GetCertNicknames (CERTCertDBHandle *handle,
+ int what, void *wincx);
+
+/*
+** Finds the crlNumber extension and decodes its value into 'value'
+*/
+extern SECStatus CERT_FindCRLNumberExten (CERTCrl *crl, CERTCrlNumber *value);
+
+extern void CERT_FreeNicknames(CERTCertNicknames *nicknames);
+
+extern PRBool CERT_CompareCerts(CERTCertificate *c1, CERTCertificate *c2);
+
+extern PRBool CERT_CompareCertsForRedirection(CERTCertificate *c1,
+ CERTCertificate *c2);
+
+/*
+** Generate an array of the Distinguished Names that the given cert database
+** "trusts"
+*/
+extern CERTDistNames *CERT_GetSSLCACerts(CERTCertDBHandle *handle);
+
+extern void CERT_FreeDistNames(CERTDistNames *names);
+
+/*
+** Generate an array of Distinguished names from an array of nicknames
+*/
+extern CERTDistNames *CERT_DistNamesFromNicknames
+ (CERTCertDBHandle *handle, char **nicknames, int nnames);
+
+/*
+** Generate a certificate chain from a certificate.
+*/
+extern CERTCertificateList *
+CERT_CertChainFromCert(CERTCertificate *cert, SECCertUsage usage,
+ PRBool includeRoot);
+
+extern CERTCertificateList *
+CERT_CertListFromCert(CERTCertificate *cert);
+
+extern CERTCertificateList *
+CERT_DupCertList(CERTCertificateList * oldList);
+
+extern void CERT_DestroyCertificateList(CERTCertificateList *list);
+
+/*
+** is cert a user cert? i.e. does it have CERTDB_USER trust,
+** i.e. a private key?
+*/
+PRBool CERT_IsUserCert(CERTCertificate* cert);
+
+/* is cert a newer than cert b? */
+PRBool CERT_IsNewer(CERTCertificate *certa, CERTCertificate *certb);
+
+/* currently a stub for address book */
+PRBool
+CERT_IsCertRevoked(CERTCertificate *cert);
+
+void
+CERT_DestroyCertArray(CERTCertificate **certs, unsigned int ncerts);
+
+/* convert an email address to lower case */
+char *CERT_FixupEmailAddr(char *emailAddr);
+
+/* decode string representation of trust flags into trust struct */
+SECStatus
+CERT_DecodeTrustString(CERTCertTrust *trust, char *trusts);
+
+/* encode trust struct into string representation of trust flags */
+char *
+CERT_EncodeTrustString(CERTCertTrust *trust);
+
+/* find the next or prev cert in a subject list */
+CERTCertificate *
+CERT_PrevSubjectCert(CERTCertificate *cert);
+CERTCertificate *
+CERT_NextSubjectCert(CERTCertificate *cert);
+
+/*
+ * import a collection of certs into the temporary or permanent cert
+ * database
+ */
+SECStatus
+CERT_ImportCerts(CERTCertDBHandle *certdb, SECCertUsage usage,
+ unsigned int ncerts, SECItem **derCerts,
+ CERTCertificate ***retCerts, PRBool keepCerts,
+ PRBool caOnly, char *nickname);
+
+SECStatus
+CERT_SaveImportedCert(CERTCertificate *cert, SECCertUsage usage,
+ PRBool caOnly, char *nickname);
+
+char *
+CERT_MakeCANickname(CERTCertificate *cert);
+
+PRBool
+CERT_IsCACert(CERTCertificate *cert, unsigned int *rettype);
+
+PRBool
+CERT_IsCADERCert(SECItem *derCert, unsigned int *rettype);
+
+PRBool
+CERT_IsRootDERCert(SECItem *derCert);
+
+SECStatus
+CERT_SaveSMimeProfile(CERTCertificate *cert, SECItem *emailProfile,
+ SECItem *profileTime);
+
+/*
+ * find the smime symmetric capabilities profile for a given cert
+ */
+SECItem *
+CERT_FindSMimeProfile(CERTCertificate *cert);
+
+SECStatus
+CERT_AddNewCerts(CERTCertDBHandle *handle);
+
+CERTPackageType
+CERT_CertPackageType(SECItem *package, SECItem *certitem);
+
+CERTCertificatePolicies *
+CERT_DecodeCertificatePoliciesExtension(SECItem *extnValue);
+
+void
+CERT_DestroyCertificatePoliciesExtension(CERTCertificatePolicies *policies);
+
+CERTUserNotice *
+CERT_DecodeUserNotice(SECItem *noticeItem);
+
+void
+CERT_DestroyUserNotice(CERTUserNotice *userNotice);
+
+typedef char * (* CERTPolicyStringCallback)(char *org,
+ unsigned long noticeNumber,
+ void *arg);
+void
+CERT_SetCAPolicyStringCallback(CERTPolicyStringCallback cb, void *cbarg);
+
+char *
+CERT_GetCertCommentString(CERTCertificate *cert);
+
+PRBool
+CERT_GovtApprovedBitSet(CERTCertificate *cert);
+
+SECStatus
+CERT_AddPermNickname(CERTCertificate *cert, char *nickname);
+
+/*
+ * Given a cert, find the cert with the same subject name that
+ * has the given key usage. If the given cert has the correct keyUsage, then
+ * return it, otherwise search the list in order.
+ */
+CERTCertificate *
+CERT_FindCertByUsage(CERTCertificate *basecert, unsigned int requiredKeyUsage);
+
+
+CERTCertList *
+CERT_MatchUserCert(CERTCertDBHandle *handle,
+ SECCertUsage usage,
+ int nCANames, char **caNames,
+ void *proto_win);
+
+CERTCertList *
+CERT_NewCertList(void);
+
+void
+CERT_DestroyCertList(CERTCertList *certs);
+
+/* remove the node and free the cert */
+void
+CERT_RemoveCertListNode(CERTCertListNode *node);
+
+SECStatus
+CERT_AddCertToListTail(CERTCertList *certs, CERTCertificate *cert);
+
+SECStatus
+CERT_AddCertToListHead(CERTCertList *certs, CERTCertificate *cert);
+
+SECStatus
+CERT_AddCertToListTailWithData(CERTCertList *certs, CERTCertificate *cert,
+ void *appData);
+
+SECStatus
+CERT_AddCertToListHeadWithData(CERTCertList *certs, CERTCertificate *cert,
+ void *appData);
+
+typedef PRBool (* CERTSortCallback)(CERTCertificate *certa,
+ CERTCertificate *certb,
+ void *arg);
+SECStatus
+CERT_AddCertToListSorted(CERTCertList *certs, CERTCertificate *cert,
+ CERTSortCallback f, void *arg);
+
+/* callback for CERT_AddCertToListSorted that sorts based on validity
+ * period and a given time.
+ */
+PRBool
+CERT_SortCBValidity(CERTCertificate *certa,
+ CERTCertificate *certb,
+ void *arg);
+
+SECStatus
+CERT_CheckForEvilCert(CERTCertificate *cert);
+
+CERTGeneralName *
+CERT_GetCertificateNames(CERTCertificate *cert, PRArenaPool *arena);
+
+int
+CERT_GetNamesLength(CERTGeneralName *names);
+
+CERTCertificate *
+CERT_CompareNameSpace(CERTCertificate *cert,
+ CERTGeneralName *namesList,
+ SECItem *namesListIndex,
+ PRArenaPool *arena,
+ CERTCertDBHandle *handle);
+
+SECStatus
+CERT_EncodeSubjectKeyID(PRArenaPool *arena, char *value, int len, SECItem *encodedValue);
+
+char *
+CERT_GetNickName(CERTCertificate *cert, CERTCertDBHandle *handle, PRArenaPool *nicknameArena);
+
+/*
+ * Creates or adds to a list of all certs with a give subject name, sorted by
+ * validity time, newest first. Invalid certs are considered older than
+ * valid certs. If validOnly is set, do not include invalid certs on list.
+ */
+CERTCertList *
+CERT_CreateSubjectCertList(CERTCertList *certList, CERTCertDBHandle *handle,
+ SECItem *name, int64 sorttime, PRBool validOnly);
+
+/*
+ * Creates or adds to a list of all certs with a give nickname, sorted by
+ * validity time, newest first. Invalid certs are considered older than valid
+ * certs. If validOnly is set, do not include invalid certs on list.
+ */
+CERTCertList *
+CERT_CreateNicknameCertList(CERTCertList *certList, CERTCertDBHandle *handle,
+ char *nickname, int64 sorttime, PRBool validOnly);
+
+/*
+ * Creates or adds to a list of all certs with a give email addr, sorted by
+ * validity time, newest first. Invalid certs are considered older than valid
+ * certs. If validOnly is set, do not include invalid certs on list.
+ */
+CERTCertList *
+CERT_CreateEmailAddrCertList(CERTCertList *certList, CERTCertDBHandle *handle,
+ char *emailAddr, int64 sorttime, PRBool validOnly);
+
+/*
+ * remove certs from a list that don't have keyUsage and certType
+ * that match the given usage.
+ */
+SECStatus
+CERT_FilterCertListByUsage(CERTCertList *certList, SECCertUsage usage,
+ PRBool ca);
+
+/*
+ * check the key usage of a cert against a set of required values
+ */
+SECStatus
+CERT_CheckKeyUsage(CERTCertificate *cert, unsigned int requiredUsage);
+
+/*
+ * return required key usage and cert type based on cert usage
+ */
+SECStatus
+CERT_KeyUsageAndTypeForCertUsage(SECCertUsage usage,
+ PRBool ca,
+ unsigned int *retKeyUsage,
+ unsigned int *retCertType);
+/*
+ * return required trust flags for various cert usages for CAs
+ */
+SECStatus
+CERT_TrustFlagsForCACertUsage(SECCertUsage usage,
+ unsigned int *retFlags,
+ SECTrustType *retTrustType);
+
+/*
+ * Find all user certificates that match the given criteria.
+ *
+ * "handle" - database to search
+ * "usage" - certificate usage to match
+ * "oneCertPerName" - if set then only return the "best" cert per
+ * name
+ * "validOnly" - only return certs that are curently valid
+ * "proto_win" - window handle passed to pkcs11
+ */
+CERTCertList *
+CERT_FindUserCertsByUsage(CERTCertDBHandle *handle,
+ SECCertUsage usage,
+ PRBool oneCertPerName,
+ PRBool validOnly,
+ void *proto_win);
+
+/*
+ * Find a user certificate that matchs the given criteria.
+ *
+ * "handle" - database to search
+ * "nickname" - nickname to match
+ * "usage" - certificate usage to match
+ * "validOnly" - only return certs that are curently valid
+ * "proto_win" - window handle passed to pkcs11
+ */
+CERTCertificate *
+CERT_FindUserCertByUsage(CERTCertDBHandle *handle,
+ char *nickname,
+ SECCertUsage usage,
+ PRBool validOnly,
+ void *proto_win);
+
+/*
+ * Filter a list of certificates, removing those certs that do not have
+ * one of the named CA certs somewhere in their cert chain.
+ *
+ * "certList" - the list of certificates to filter
+ * "nCANames" - number of CA names
+ * "caNames" - array of CA names in string(rfc 1485) form
+ * "usage" - what use the certs are for, this is used when
+ * selecting CA certs
+ */
+SECStatus
+CERT_FilterCertListByCANames(CERTCertList *certList, int nCANames,
+ char **caNames, SECCertUsage usage);
+
+/*
+ * Filter a list of certificates, removing those certs that aren't user certs
+ */
+SECStatus
+CERT_FilterCertListForUserCerts(CERTCertList *certList);
+
+/*
+ * Collect the nicknames from all certs in a CertList. If the cert is not
+ * valid, append a string to that nickname.
+ *
+ * "certList" - the list of certificates
+ * "expiredString" - the string to append to the nickname of any expired cert
+ * "notYetGoodString" - the string to append to the nickname of any cert
+ * that is not yet valid
+ */
+CERTCertNicknames *
+CERT_NicknameStringsFromCertList(CERTCertList *certList, char *expiredString,
+ char *notYetGoodString);
+
+/*
+ * Extract the nickname from a nickmake string that may have either
+ * expiredString or notYetGoodString appended.
+ *
+ * Args:
+ * "namestring" - the string containing the nickname, and possibly
+ * one of the validity label strings
+ * "expiredString" - the expired validity label string
+ * "notYetGoodString" - the not yet good validity label string
+ *
+ * Returns the raw nickname
+ */
+char *
+CERT_ExtractNicknameString(char *namestring, char *expiredString,
+ char *notYetGoodString);
+
+/*
+ * Given a certificate, return a string containing the nickname, and possibly
+ * one of the validity strings, based on the current validity state of the
+ * certificate.
+ *
+ * "arena" - arena to allocate returned string from. If NULL, then heap
+ * is used.
+ * "cert" - the cert to get nickname from
+ * "expiredString" - the string to append to the nickname if the cert is
+ * expired.
+ * "notYetGoodString" - the string to append to the nickname if the cert is
+ * not yet good.
+ */
+char *
+CERT_GetCertNicknameWithValidity(PRArenaPool *arena, CERTCertificate *cert,
+ char *expiredString, char *notYetGoodString);
+
+/*
+ * Return the string representation of a DER encoded distinguished name
+ * "dername" - The DER encoded name to convert
+ */
+char *
+CERT_DerNameToAscii(SECItem *dername);
+
+/*
+ * Supported usage values and types:
+ * certUsageSSLClient
+ * certUsageSSLServer
+ * certUsageSSLServerWithStepUp
+ * certUsageEmailSigner
+ * certUsageEmailRecipient
+ * certUsageObjectSigner
+ */
+
+CERTCertificate *
+CERT_FindMatchingCert(CERTCertDBHandle *handle, SECItem *derName,
+ CERTCertOwner owner, SECCertUsage usage,
+ PRBool preferTrusted, int64 validTime, PRBool validOnly);
+
+
+/*********************************************************************/
+/* A thread safe implementation of General Names */
+/*********************************************************************/
+
+/* Destroy a Single CERTGeneralName */
+void
+CERT_DestroyGeneralName(CERTGeneralName *name);
+
+/* Destroys a CERTGeneralNameList */
+void
+CERT_DestroyGeneralNameList(CERTGeneralNameList *list);
+
+/* Creates a CERTGeneralNameList */
+CERTGeneralNameList *
+CERT_CreateGeneralNameList(CERTGeneralName *name);
+
+/* Compares two CERTGeneralNameList */
+SECStatus
+CERT_CompareGeneralNameLists(CERTGeneralNameList *a, CERTGeneralNameList *b);
+
+/* returns a copy of the first name of the type requested */
+void *
+CERT_GetGeneralNameFromListByType(CERTGeneralNameList *list,
+ CERTGeneralNameType type,
+ PRArenaPool *arena);
+
+/* Adds a name to the tail of the list */
+void
+CERT_AddGeneralNameToList(CERTGeneralNameList *list,
+ CERTGeneralNameType type,
+ void *data, SECItem *oid);
+
+/* returns a duplicate of the CERTGeneralNameList */
+CERTGeneralNameList *
+CERT_DupGeneralNameList(CERTGeneralNameList *list);
+
+/* returns the length of a CERTGeneralName */
+int
+CERT_GetNamesLength(CERTGeneralName *names);
+
+/*
+ * Acquire the global lock on the cert database.
+ * This lock is currently used for the following operations:
+ * adding or deleting a cert to either the temp or perm databases
+ * converting a temp to perm or perm to temp
+ * changing(maybe just adding?) the trust of a cert
+ * adjusting the reference count of a cert
+ */
+void
+CERT_LockDB(CERTCertDBHandle *handle);
+
+/*
+ * Free the global cert database lock.
+ */
+void
+CERT_UnlockDB(CERTCertDBHandle *handle);
+
+/*
+ * Get the certificate status checking configuratino data for
+ * the certificate database
+ */
+CERTStatusConfig *
+CERT_GetStatusConfig(CERTCertDBHandle *handle);
+
+/*
+ * Set the certificate status checking information for the
+ * database. The input structure becomes part of the certificate
+ * database and will be freed by calling the 'Destroy' function in
+ * the configuration object.
+ */
+void
+CERT_SetStatusConfig(CERTCertDBHandle *handle, CERTStatusConfig *config);
+
+
+
+/*
+ * Acquire the cert reference count lock
+ * There is currently one global lock for all certs, but I'm putting a cert
+ * arg here so that it will be easy to make it per-cert in the future if
+ * that turns out to be necessary.
+ */
+void
+CERT_LockCertRefCount(CERTCertificate *cert);
+
+/*
+ * Free the cert reference count lock
+ */
+void
+CERT_UnlockCertRefCount(CERTCertificate *cert);
+
+/*
+ * Acquire the cert trust lock
+ * There is currently one global lock for all certs, but I'm putting a cert
+ * arg here so that it will be easy to make it per-cert in the future if
+ * that turns out to be necessary.
+ */
+void
+CERT_LockCertTrust(CERTCertificate *cert);
+
+/*
+ * Free the cert trust lock
+ */
+void
+CERT_UnlockCertTrust(CERTCertificate *cert);
+
+/*
+ * Digest the cert's subject public key using the specified algorithm.
+ * The necessary storage for the digest data is allocated. If "fill" is
+ * non-null, the data is put there, otherwise a SECItem is allocated.
+ * Allocation from "arena" if it is non-null, heap otherwise. Any problem
+ * results in a NULL being returned (and an appropriate error set).
+ */
+extern SECItem *
+CERT_SPKDigestValueForCert(PRArenaPool *arena, CERTCertificate *cert,
+ SECOidTag digestAlg, SECItem *fill);
+
+/*
+ * fill in nsCertType field of the cert based on the cert extension
+ */
+extern SECStatus cert_GetCertType(CERTCertificate *cert);
+
+
+SECStatus CERT_CheckCRL(CERTCertificate* cert, CERTCertificate* issuer,
+ SECItem* dp, int64 t, void* wincx);
+
+
+SEC_END_PROTOS
+
+#endif /* _CERT_H_ */
diff --git a/security/nss/lib/certdb/certdb.c b/security/nss/lib/certdb/certdb.c
new file mode 100644
index 000000000..76c13e2de
--- /dev/null
+++ b/security/nss/lib/certdb/certdb.c
@@ -0,0 +1,2918 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+ * Certificate handling code
+ *
+ * $Id$
+ */
+
+#include "nssilock.h"
+#include "prmon.h"
+#include "prtime.h"
+#include "cert.h"
+#include "certi.h"
+#include "secder.h"
+#include "secoid.h"
+#include "secasn1.h"
+#include "genname.h"
+#include "keyhi.h"
+#include "secitem.h"
+#include "mcom_db.h"
+#include "certdb.h"
+#include "prprf.h"
+#include "sechash.h"
+#include "prlong.h"
+#include "certxutl.h"
+#include "portreg.h"
+#include "secerr.h"
+#include "sslerr.h"
+#include "nsslocks.h"
+#include "pk11func.h"
+#include "xconst.h" /* for CERT_DecodeAltNameExtension */
+
+#ifndef NSS_3_4_CODE
+#define NSS_3_4_CODE
+#endif /* NSS_3_4_CODE */
+#include "pki.h"
+#include "pki3hack.h"
+
+/*
+ * Certificate database handling code
+ */
+
+
+const SEC_ASN1Template CERT_CertExtensionTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTCertExtension) },
+ { SEC_ASN1_OBJECT_ID,
+ offsetof(CERTCertExtension,id) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, /* XXX DER_DEFAULT */
+ offsetof(CERTCertExtension,critical) },
+ { SEC_ASN1_OCTET_STRING,
+ offsetof(CERTCertExtension,value) },
+ { 0, }
+};
+
+const SEC_ASN1Template CERT_SequenceOfCertExtensionTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, CERT_CertExtensionTemplate }
+};
+
+const SEC_ASN1Template CERT_CertificateTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTCertificate) },
+ { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
+ SEC_ASN1_CONTEXT_SPECIFIC | 0, /* XXX DER_DEFAULT */
+ offsetof(CERTCertificate,version),
+ SEC_IntegerTemplate },
+ { SEC_ASN1_INTEGER,
+ offsetof(CERTCertificate,serialNumber) },
+ { SEC_ASN1_INLINE,
+ offsetof(CERTCertificate,signature),
+ SECOID_AlgorithmIDTemplate },
+ { SEC_ASN1_SAVE,
+ offsetof(CERTCertificate,derIssuer) },
+ { SEC_ASN1_INLINE,
+ offsetof(CERTCertificate,issuer),
+ CERT_NameTemplate },
+ { SEC_ASN1_INLINE,
+ offsetof(CERTCertificate,validity),
+ CERT_ValidityTemplate },
+ { SEC_ASN1_SAVE,
+ offsetof(CERTCertificate,derSubject) },
+ { SEC_ASN1_INLINE,
+ offsetof(CERTCertificate,subject),
+ CERT_NameTemplate },
+ { SEC_ASN1_SAVE,
+ offsetof(CERTCertificate,derPublicKey) },
+ { SEC_ASN1_INLINE,
+ offsetof(CERTCertificate,subjectPublicKeyInfo),
+ CERT_SubjectPublicKeyInfoTemplate },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
+ offsetof(CERTCertificate,issuerID),
+ SEC_ObjectIDTemplate },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 2,
+ offsetof(CERTCertificate,subjectID),
+ SEC_ObjectIDTemplate },
+ { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
+ SEC_ASN1_CONTEXT_SPECIFIC | 3,
+ offsetof(CERTCertificate,extensions),
+ CERT_SequenceOfCertExtensionTemplate },
+ { 0 }
+};
+
+const SEC_ASN1Template SEC_SignedCertificateTemplate[] =
+{
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTCertificate) },
+ { SEC_ASN1_SAVE,
+ offsetof(CERTCertificate,signatureWrap.data) },
+ { SEC_ASN1_INLINE,
+ 0, CERT_CertificateTemplate },
+ { SEC_ASN1_INLINE,
+ offsetof(CERTCertificate,signatureWrap.signatureAlgorithm),
+ SECOID_AlgorithmIDTemplate },
+ { SEC_ASN1_BIT_STRING,
+ offsetof(CERTCertificate,signatureWrap.signature) },
+ { 0 }
+};
+
+/*
+ * Find the subjectName in a DER encoded certificate
+ */
+const SEC_ASN1Template SEC_CertSubjectTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(SECItem) },
+ { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
+ SEC_ASN1_CONTEXT_SPECIFIC | 0,
+ 0, SEC_SkipTemplate }, /* version */
+ { SEC_ASN1_SKIP }, /* serial number */
+ { SEC_ASN1_SKIP }, /* signature algorithm */
+ { SEC_ASN1_SKIP }, /* issuer */
+ { SEC_ASN1_SKIP }, /* validity */
+ { SEC_ASN1_ANY, 0, NULL }, /* subject */
+ { SEC_ASN1_SKIP_REST },
+ { 0 }
+};
+
+/*
+ * Find the issuerName in a DER encoded certificate
+ */
+const SEC_ASN1Template SEC_CertIssuerTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(SECItem) },
+ { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
+ SEC_ASN1_CONTEXT_SPECIFIC | 0,
+ 0, SEC_SkipTemplate }, /* version */
+ { SEC_ASN1_SKIP }, /* serial number */
+ { SEC_ASN1_SKIP }, /* signature algorithm */
+ { SEC_ASN1_ANY, 0, NULL }, /* issuer */
+ { SEC_ASN1_SKIP_REST },
+ { 0 }
+};
+/*
+ * Find the subjectName in a DER encoded certificate
+ */
+const SEC_ASN1Template SEC_CertSerialNumberTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(SECItem) },
+ { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
+ SEC_ASN1_CONTEXT_SPECIFIC | 0,
+ 0, SEC_SkipTemplate }, /* version */
+ { SEC_ASN1_ANY, 0, NULL }, /* serial number */
+ { SEC_ASN1_SKIP_REST },
+ { 0 }
+};
+
+/*
+ * Find the issuer and serialNumber in a DER encoded certificate.
+ * This data is used as the database lookup key since its the unique
+ * identifier of a certificate.
+ */
+const SEC_ASN1Template CERT_CertKeyTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTCertKey) },
+ { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
+ SEC_ASN1_CONTEXT_SPECIFIC | 0,
+ 0, SEC_SkipTemplate }, /* version */
+ { SEC_ASN1_INTEGER,
+ offsetof(CERTCertKey,serialNumber) },
+ { SEC_ASN1_SKIP }, /* signature algorithm */
+ { SEC_ASN1_ANY,
+ offsetof(CERTCertKey,derIssuer) },
+ { SEC_ASN1_SKIP_REST },
+ { 0 }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CertificateTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SignedCertificateTemplate)
+
+SECStatus
+CERT_KeyFromIssuerAndSN(PRArenaPool *arena, SECItem *issuer, SECItem *sn,
+ SECItem *key)
+{
+ key->len = sn->len + issuer->len;
+
+ if ((sn->data == NULL) || (issuer->data == NULL)) {
+ goto loser;
+ }
+
+ key->data = (unsigned char*)PORT_ArenaAlloc(arena, key->len);
+ if ( !key->data ) {
+ goto loser;
+ }
+
+ /* copy the serialNumber */
+ PORT_Memcpy(key->data, sn->data, sn->len);
+
+ /* copy the issuer */
+ PORT_Memcpy(&key->data[sn->len], issuer->data, issuer->len);
+
+ return(SECSuccess);
+
+loser:
+ return(SECFailure);
+}
+
+
+/*
+ * Extract the subject name from a DER certificate
+ */
+SECStatus
+CERT_NameFromDERCert(SECItem *derCert, SECItem *derName)
+{
+ int rv;
+ PRArenaPool *arena;
+ CERTSignedData sd;
+ void *tmpptr;
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+
+ if ( ! arena ) {
+ return(SECFailure);
+ }
+
+ PORT_Memset(&sd, 0, sizeof(CERTSignedData));
+ rv = SEC_QuickDERDecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert);
+
+ if ( rv ) {
+ goto loser;
+ }
+
+ PORT_Memset(derName, 0, sizeof(SECItem));
+ rv = SEC_QuickDERDecodeItem(arena, derName, SEC_CertSubjectTemplate, &sd.data);
+
+ if ( rv ) {
+ goto loser;
+ }
+
+ tmpptr = derName->data;
+ derName->data = (unsigned char*)PORT_Alloc(derName->len);
+ if ( derName->data == NULL ) {
+ goto loser;
+ }
+
+ PORT_Memcpy(derName->data, tmpptr, derName->len);
+
+ PORT_FreeArena(arena, PR_FALSE);
+ return(SECSuccess);
+
+loser:
+ PORT_FreeArena(arena, PR_FALSE);
+ return(SECFailure);
+}
+
+SECStatus
+CERT_IssuerNameFromDERCert(SECItem *derCert, SECItem *derName)
+{
+ int rv;
+ PRArenaPool *arena;
+ CERTSignedData sd;
+ void *tmpptr;
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+
+ if ( ! arena ) {
+ return(SECFailure);
+ }
+
+ PORT_Memset(&sd, 0, sizeof(CERTSignedData));
+ rv = SEC_QuickDERDecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert);
+
+ if ( rv ) {
+ goto loser;
+ }
+
+ PORT_Memset(derName, 0, sizeof(SECItem));
+ rv = SEC_QuickDERDecodeItem(arena, derName, SEC_CertIssuerTemplate, &sd.data);
+
+ if ( rv ) {
+ goto loser;
+ }
+
+ tmpptr = derName->data;
+ derName->data = (unsigned char*)PORT_Alloc(derName->len);
+ if ( derName->data == NULL ) {
+ goto loser;
+ }
+
+ PORT_Memcpy(derName->data, tmpptr, derName->len);
+
+ PORT_FreeArena(arena, PR_FALSE);
+ return(SECSuccess);
+
+loser:
+ PORT_FreeArena(arena, PR_FALSE);
+ return(SECFailure);
+}
+
+SECStatus
+CERT_SerialNumberFromDERCert(SECItem *derCert, SECItem *derName)
+{
+ int rv;
+ PRArenaPool *arena;
+ CERTSignedData sd;
+ void *tmpptr;
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+
+ if ( ! arena ) {
+ return(SECFailure);
+ }
+
+ PORT_Memset(&sd, 0, sizeof(CERTSignedData));
+ rv = SEC_QuickDERDecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert);
+
+ if ( rv ) {
+ goto loser;
+ }
+
+ PORT_Memset(derName, 0, sizeof(SECItem));
+ rv = SEC_QuickDERDecodeItem(arena, derName, SEC_CertSerialNumberTemplate, &sd.data);
+
+ if ( rv ) {
+ goto loser;
+ }
+
+ tmpptr = derName->data;
+ derName->data = (unsigned char*)PORT_Alloc(derName->len);
+ if ( derName->data == NULL ) {
+ goto loser;
+ }
+
+ PORT_Memcpy(derName->data, tmpptr, derName->len);
+
+ PORT_FreeArena(arena, PR_FALSE);
+ return(SECSuccess);
+
+loser:
+ PORT_FreeArena(arena, PR_FALSE);
+ return(SECFailure);
+}
+
+/*
+ * Generate a database key, based on serial number and issuer, from a
+ * DER certificate.
+ */
+SECStatus
+CERT_KeyFromDERCert(PRArenaPool *arena, SECItem *derCert, SECItem *key)
+{
+ int rv;
+ CERTSignedData sd;
+ CERTCertKey certkey;
+
+ PORT_Memset(&sd, 0, sizeof(CERTSignedData));
+ rv = SEC_ASN1DecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert);
+
+ if ( rv ) {
+ goto loser;
+ }
+
+ PORT_Memset(&certkey, 0, sizeof(CERTCertKey));
+ rv = SEC_ASN1DecodeItem(arena, &certkey, CERT_CertKeyTemplate, &sd.data);
+
+ if ( rv ) {
+ goto loser;
+ }
+
+ return(CERT_KeyFromIssuerAndSN(arena, &certkey.derIssuer,
+ &certkey.serialNumber, key));
+loser:
+ return(SECFailure);
+}
+
+/*
+ * fill in keyUsage field of the cert based on the cert extension
+ * if the extension is not critical, then we allow all uses
+ */
+static SECStatus
+GetKeyUsage(CERTCertificate *cert)
+{
+ SECStatus rv;
+ SECItem tmpitem;
+
+ rv = CERT_FindKeyUsageExtension(cert, &tmpitem);
+ if ( rv == SECSuccess ) {
+ /* remember the actual value of the extension */
+ cert->rawKeyUsage = tmpitem.data[0];
+ cert->keyUsagePresent = PR_TRUE;
+ cert->keyUsage = tmpitem.data[0];
+
+ PORT_Free(tmpitem.data);
+ tmpitem.data = NULL;
+
+ } else {
+ /* if the extension is not present, then we allow all uses */
+ cert->keyUsage = KU_ALL;
+ cert->rawKeyUsage = KU_ALL;
+ cert->keyUsagePresent = PR_FALSE;
+ }
+
+ if ( CERT_GovtApprovedBitSet(cert) ) {
+ cert->keyUsage |= KU_NS_GOVT_APPROVED;
+ cert->rawKeyUsage |= KU_NS_GOVT_APPROVED;
+ }
+
+ return(SECSuccess);
+}
+
+
+/*
+ * determine if a fortezza V1 Cert is a CA or not.
+ */
+static PRBool
+fortezzaIsCA( CERTCertificate *cert) {
+ PRBool isCA = PR_FALSE;
+ CERTSubjectPublicKeyInfo *spki = &cert->subjectPublicKeyInfo;
+ int tag;
+
+ tag = SECOID_GetAlgorithmTag(&spki->algorithm);
+ if ((tag == SEC_OID_MISSI_KEA_DSS_OLD) ||
+ (tag == SEC_OID_MISSI_KEA_DSS) ||
+ (tag == SEC_OID_MISSI_DSS_OLD) ||
+ (tag == SEC_OID_MISSI_DSS) ) {
+ SECItem rawkey;
+ unsigned char *rawptr;
+ unsigned char *end;
+ int len;
+
+ rawkey = spki->subjectPublicKey;
+ DER_ConvertBitString(&rawkey);
+ rawptr = rawkey.data;
+ end = rawkey.data + rawkey.len;
+
+ /* version */
+ rawptr += sizeof(((SECKEYPublicKey*)0)->u.fortezza.KMID)+2;
+
+ /* clearance (the string up to the first byte with the hi-bit on */
+ while ((rawptr < end) && (*rawptr++ & 0x80));
+ if (rawptr >= end) { return PR_FALSE; }
+
+ /* KEAPrivilege (the string up to the first byte with the hi-bit on */
+ while ((rawptr < end) && (*rawptr++ & 0x80));
+ if (rawptr >= end) { return PR_FALSE; }
+
+ /* skip the key */
+ len = (*rawptr << 8) | rawptr[1];
+ rawptr += 2 + len;
+
+ /* shared key */
+ if (rawptr >= end) { return PR_FALSE; }
+ /* DSS Version is next */
+ rawptr += 2;
+
+ /* DSSPrivilege (the string up to the first byte with the hi-bit on */
+ if (*rawptr & 0x30) isCA = PR_TRUE;
+
+ }
+ return isCA;
+}
+
+static SECStatus
+findOIDinOIDSeqByTagNum(CERTOidSequence *seq, SECOidTag tagnum)
+{
+ SECItem **oids;
+ SECItem *oid;
+ SECStatus rv = SECFailure;
+
+ if (seq != NULL) {
+ oids = seq->oids;
+ while (oids != NULL && *oids != NULL) {
+ oid = *oids;
+ if (SECOID_FindOIDTag(oid) == tagnum) {
+ rv = SECSuccess;
+ break;
+ }
+ oids++;
+ }
+ }
+ return rv;
+}
+
+/*
+ * fill in nsCertType field of the cert based on the cert extension
+ */
+SECStatus
+cert_GetCertType(CERTCertificate *cert)
+{
+ SECStatus rv;
+ SECItem tmpitem;
+ SECItem encodedExtKeyUsage;
+ CERTOidSequence *extKeyUsage = NULL;
+ PRBool basicConstraintPresent = PR_FALSE;
+ CERTBasicConstraints basicConstraint;
+ unsigned int nsCertType = 0;
+
+ if (cert->nsCertType) {
+ /* once set, no need to recalculate */
+ return SECSuccess;
+ }
+
+ tmpitem.data = NULL;
+ CERT_FindNSCertTypeExtension(cert, &tmpitem);
+ rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE,
+ &encodedExtKeyUsage);
+ if (rv == SECSuccess) {
+ extKeyUsage = CERT_DecodeOidSequence(&encodedExtKeyUsage);
+ }
+ rv = CERT_FindBasicConstraintExten(cert, &basicConstraint);
+ if (rv == SECSuccess) {
+ basicConstraintPresent = PR_TRUE;
+ }
+ if (tmpitem.data != NULL || extKeyUsage != NULL) {
+ if (tmpitem.data == NULL) {
+ nsCertType = 0;
+ } else {
+ nsCertType = tmpitem.data[0];
+ }
+
+ /* free tmpitem data pointer to avoid memory leak */
+ PORT_Free(tmpitem.data);
+ tmpitem.data = NULL;
+
+ /*
+ * for this release, we will allow SSL certs with an email address
+ * to be used for email
+ */
+ if ( ( nsCertType & NS_CERT_TYPE_SSL_CLIENT ) &&
+ cert->emailAddr ) {
+ nsCertType |= NS_CERT_TYPE_EMAIL;
+ }
+ /*
+ * for this release, we will allow SSL intermediate CAs to be
+ * email intermediate CAs too.
+ */
+ if ( nsCertType & NS_CERT_TYPE_SSL_CA ) {
+ nsCertType |= NS_CERT_TYPE_EMAIL_CA;
+ }
+ /*
+ * allow a cert with the extended key usage of EMail Protect
+ * to be used for email or as an email CA, if basic constraints
+ * indicates that it is a CA.
+ */
+ if (findOIDinOIDSeqByTagNum(extKeyUsage,
+ SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT) ==
+ SECSuccess) {
+ if (basicConstraintPresent == PR_TRUE &&
+ (basicConstraint.isCA)) {
+ nsCertType |= NS_CERT_TYPE_EMAIL_CA;
+ } else {
+ nsCertType |= NS_CERT_TYPE_EMAIL;
+ }
+ }
+ if (findOIDinOIDSeqByTagNum(extKeyUsage,
+ SEC_OID_EXT_KEY_USAGE_SERVER_AUTH) ==
+ SECSuccess){
+ if (basicConstraintPresent == PR_TRUE &&
+ (basicConstraint.isCA)) {
+ nsCertType |= NS_CERT_TYPE_SSL_CA;
+ } else {
+ nsCertType |= NS_CERT_TYPE_SSL_SERVER;
+ }
+ }
+ if (findOIDinOIDSeqByTagNum(extKeyUsage,
+ SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH) ==
+ SECSuccess){
+ if (basicConstraintPresent == PR_TRUE &&
+ (basicConstraint.isCA)) {
+ nsCertType |= NS_CERT_TYPE_SSL_CA;
+ } else {
+ nsCertType |= NS_CERT_TYPE_SSL_CLIENT;
+ }
+ }
+ if (findOIDinOIDSeqByTagNum(extKeyUsage,
+ SEC_OID_EXT_KEY_USAGE_CODE_SIGN) ==
+ SECSuccess) {
+ if (basicConstraintPresent == PR_TRUE &&
+ (basicConstraint.isCA)) {
+ nsCertType |= NS_CERT_TYPE_OBJECT_SIGNING_CA;
+ } else {
+ nsCertType |= NS_CERT_TYPE_OBJECT_SIGNING;
+ }
+ }
+ if (findOIDinOIDSeqByTagNum(extKeyUsage,
+ SEC_OID_EXT_KEY_USAGE_TIME_STAMP) ==
+ SECSuccess) {
+ nsCertType |= EXT_KEY_USAGE_TIME_STAMP;
+ }
+ if (findOIDinOIDSeqByTagNum(extKeyUsage,
+ SEC_OID_OCSP_RESPONDER) ==
+ SECSuccess) {
+ nsCertType |= EXT_KEY_USAGE_STATUS_RESPONDER;
+ }
+ } else {
+ /* if no extension, then allow any ssl or email (no ca or object
+ * signing)
+ */
+ nsCertType = NS_CERT_TYPE_SSL_CLIENT | NS_CERT_TYPE_SSL_SERVER |
+ NS_CERT_TYPE_EMAIL;
+
+ /* if the basic constraint extension says the cert is a CA, then
+ allow SSL CA and EMAIL CA and Status Responder */
+ if ((basicConstraintPresent == PR_TRUE)
+ && (basicConstraint.isCA)) {
+ nsCertType |= NS_CERT_TYPE_SSL_CA;
+ nsCertType |= NS_CERT_TYPE_EMAIL_CA;
+ nsCertType |= EXT_KEY_USAGE_STATUS_RESPONDER;
+ } else if (CERT_IsCACert(cert, NULL) == PR_TRUE) {
+ nsCertType |= EXT_KEY_USAGE_STATUS_RESPONDER;
+ }
+
+ /* if the cert is a fortezza CA cert, then allow SSL CA and EMAIL CA */
+ if (fortezzaIsCA(cert)) {
+ nsCertType |= NS_CERT_TYPE_SSL_CA;
+ nsCertType |= NS_CERT_TYPE_EMAIL_CA;
+ }
+ }
+
+ if (extKeyUsage != NULL) {
+ PORT_Free(encodedExtKeyUsage.data);
+ CERT_DestroyOidSequence(extKeyUsage);
+ }
+ PR_AtomicSet(&cert->nsCertType, nsCertType);
+ return(SECSuccess);
+}
+
+/*
+ * cert_GetKeyID() - extract or generate the subjectKeyID from a certificate
+ */
+SECStatus
+cert_GetKeyID(CERTCertificate *cert)
+{
+ SECItem tmpitem;
+ SECStatus rv;
+ SECKEYPublicKey *key;
+
+ cert->subjectKeyID.len = 0;
+
+ /* see of the cert has a key identifier extension */
+ rv = CERT_FindSubjectKeyIDExtension(cert, &tmpitem);
+ if ( rv == SECSuccess ) {
+ cert->subjectKeyID.data = (unsigned char*) PORT_ArenaAlloc(cert->arena, tmpitem.len);
+ if ( cert->subjectKeyID.data != NULL ) {
+ PORT_Memcpy(cert->subjectKeyID.data, tmpitem.data, tmpitem.len);
+ cert->subjectKeyID.len = tmpitem.len;
+ cert->keyIDGenerated = PR_FALSE;
+ }
+
+ PORT_Free(tmpitem.data);
+ }
+
+ /* if the cert doesn't have a key identifier extension and the cert is
+ * a V1 fortezza certificate, use the cert's 8 byte KMID as the
+ * key identifier. */
+ key = CERT_KMIDPublicKey(cert);
+
+ if (key != NULL) {
+
+ if (key->keyType == fortezzaKey) {
+
+ cert->subjectKeyID.data = (unsigned char *)PORT_ArenaAlloc(cert->arena, 8);
+ if ( cert->subjectKeyID.data != NULL ) {
+ PORT_Memcpy(cert->subjectKeyID.data, key->u.fortezza.KMID, 8);
+ cert->subjectKeyID.len = 8;
+ cert->keyIDGenerated = PR_FALSE;
+ }
+ }
+
+ SECKEY_DestroyPublicKey(key);
+ }
+
+ /* if the cert doesn't have a key identifier extension, then generate one*/
+ if ( cert->subjectKeyID.len == 0 ) {
+ /*
+ * pkix says that if the subjectKeyID is not present, then we should
+ * use the SHA-1 hash of the DER-encoded publicKeyInfo from the cert
+ */
+ cert->subjectKeyID.data = (unsigned char *)PORT_ArenaAlloc(cert->arena, SHA1_LENGTH);
+ if ( cert->subjectKeyID.data != NULL ) {
+ rv = PK11_HashBuf(SEC_OID_SHA1,cert->subjectKeyID.data,
+ cert->derPublicKey.data,
+ cert->derPublicKey.len);
+ if ( rv == SECSuccess ) {
+ cert->subjectKeyID.len = SHA1_LENGTH;
+ }
+ }
+ }
+
+ if ( cert->subjectKeyID.len == 0 ) {
+ return(SECFailure);
+ }
+ return(SECSuccess);
+
+}
+
+static PRBool
+cert_IsRootCert(CERTCertificate *cert)
+{
+ SECStatus rv;
+ SECItem tmpitem;
+
+ /* cache the authKeyID extension, if present */
+ cert->authKeyID = CERT_FindAuthKeyIDExten(cert->arena, cert);
+
+ /* it MUST be self-issued to be a root */
+ if (cert->derIssuer.len == 0 ||
+ !SECITEM_ItemsAreEqual(&cert->derIssuer, &cert->derSubject))
+ {
+ return PR_FALSE;
+ }
+
+ /* check the authKeyID extension */
+ if (cert->authKeyID) {
+ /* authority key identifier is present */
+ if (cert->authKeyID->keyID.len > 0) {
+ /* the keyIdentifier field is set, look for subjectKeyID */
+ rv = CERT_FindSubjectKeyIDExtension(cert, &tmpitem);
+ if (rv == SECSuccess) {
+ PRBool match;
+ /* also present, they MUST match for it to be a root */
+ match = SECITEM_ItemsAreEqual(&cert->authKeyID->keyID,
+ &tmpitem);
+ PORT_Free(tmpitem.data);
+ if (!match) return PR_FALSE; /* else fall through */
+ } else {
+ /* the subject key ID is required when AKI is present */
+ return PR_FALSE;
+ }
+ }
+ if (cert->authKeyID->authCertIssuer) {
+ SECItem *caName;
+ caName = (SECItem *)CERT_GetGeneralNameByType(
+ cert->authKeyID->authCertIssuer,
+ certDirectoryName, PR_TRUE);
+ if (caName) {
+ if (!SECITEM_ItemsAreEqual(&cert->derIssuer, caName)) {
+ return PR_FALSE;
+ } /* else fall through */
+ } /* else ??? could not get general name as directory name? */
+ }
+ if (cert->authKeyID->authCertSerialNumber.len > 0) {
+ if (!SECITEM_ItemsAreEqual(&cert->serialNumber,
+ &cert->authKeyID->authCertSerialNumber)) {
+ return PR_FALSE;
+ } /* else fall through */
+ }
+ /* all of the AKI fields that were present passed the test */
+ return PR_TRUE;
+ }
+ /* else the AKI was not present, so this is a root */
+ return PR_TRUE;
+}
+
+/*
+ * take a DER certificate and decode it into a certificate structure
+ */
+CERTCertificate *
+CERT_DecodeDERCertificate(SECItem *derSignedCert, PRBool copyDER,
+ char *nickname)
+{
+ CERTCertificate *cert;
+ PRArenaPool *arena;
+ void *data;
+ int rv;
+ int len;
+ char *tmpname;
+
+ /* make a new arena */
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+
+ if ( !arena ) {
+ return 0;
+ }
+
+ /* allocate the certificate structure */
+ cert = (CERTCertificate *)PORT_ArenaZAlloc(arena, sizeof(CERTCertificate));
+
+ if ( !cert ) {
+ goto loser;
+ }
+
+ cert->arena = arena;
+
+ if ( copyDER ) {
+ /* copy the DER data for the cert into this arena */
+ data = (void *)PORT_ArenaAlloc(arena, derSignedCert->len);
+ if ( !data ) {
+ goto loser;
+ }
+ cert->derCert.data = (unsigned char *)data;
+ cert->derCert.len = derSignedCert->len;
+ PORT_Memcpy(data, derSignedCert->data, derSignedCert->len);
+ } else {
+ /* point to passed in DER data */
+ cert->derCert = *derSignedCert;
+ }
+
+ /* decode the certificate info */
+ rv = SEC_QuickDERDecodeItem(arena, cert, SEC_SignedCertificateTemplate,
+ &cert->derCert);
+
+ if ( rv ) {
+ goto loser;
+ }
+
+ if (cert_HasUnknownCriticalExten (cert->extensions) == PR_TRUE) {
+ PORT_SetError(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
+ goto loser;
+ }
+
+ /* generate and save the database key for the cert */
+ rv = CERT_KeyFromIssuerAndSN(arena, &cert->derIssuer, &cert->serialNumber,
+ &cert->certKey);
+ if ( rv ) {
+ goto loser;
+ }
+
+ /* set the nickname */
+ if ( nickname == NULL ) {
+ cert->nickname = NULL;
+ } else {
+ /* copy and install the nickname */
+ len = PORT_Strlen(nickname) + 1;
+ cert->nickname = (char*)PORT_ArenaAlloc(arena, len);
+ if ( cert->nickname == NULL ) {
+ goto loser;
+ }
+
+ PORT_Memcpy(cert->nickname, nickname, len);
+ }
+
+ /* set the email address */
+ cert->emailAddr = cert_GetCertificateEmailAddresses(cert);
+
+ /* initialize the subjectKeyID */
+ rv = cert_GetKeyID(cert);
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ /* initialize keyUsage */
+ rv = GetKeyUsage(cert);
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ /* initialize the certType */
+ rv = cert_GetCertType(cert);
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ /* determine if this is a root cert */
+ cert->isRoot = cert_IsRootCert(cert);
+
+ tmpname = CERT_NameToAscii(&cert->subject);
+ if ( tmpname != NULL ) {
+ cert->subjectName = PORT_ArenaStrdup(cert->arena, tmpname);
+ PORT_Free(tmpname);
+ }
+
+ tmpname = CERT_NameToAscii(&cert->issuer);
+ if ( tmpname != NULL ) {
+ cert->issuerName = PORT_ArenaStrdup(cert->arena, tmpname);
+ PORT_Free(tmpname);
+ }
+
+ cert->referenceCount = 1;
+ cert->slot = NULL;
+ cert->pkcs11ID = CK_INVALID_HANDLE;
+ cert->dbnickname = NULL;
+
+ return(cert);
+
+loser:
+
+ if ( arena ) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ return(0);
+}
+
+CERTCertificate *
+__CERT_DecodeDERCertificate(SECItem *derSignedCert, PRBool copyDER,
+ char *nickname)
+{
+ return CERT_DecodeDERCertificate(derSignedCert, copyDER, nickname);
+}
+
+
+/*
+** Amount of time that a certifiate is allowed good before it is actually
+** good. This is used for pending certificates, ones that are about to be
+** valid. The slop is designed to allow for some variance in the clocks
+** of the machine checking the certificate.
+*/
+#define PENDING_SLOP (24L*60L*60L) /* seconds per day */
+static PRInt32 pendingSlop = PENDING_SLOP; /* seconds */
+
+PRInt32
+CERT_GetSlopTime(void)
+{
+ return pendingSlop; /* seconds */
+}
+
+SECStatus
+CERT_SetSlopTime(PRInt32 slop) /* seconds */
+{
+ if (slop < 0)
+ return SECFailure;
+ pendingSlop = slop;
+ return SECSuccess;
+}
+
+SECStatus
+CERT_GetCertTimes(CERTCertificate *c, PRTime *notBefore, PRTime *notAfter)
+{
+ int rv;
+
+ /* convert DER not-before time */
+ rv = DER_UTCTimeToTime(notBefore, &c->validity.notBefore);
+ if (rv) {
+ return(SECFailure);
+ }
+
+ /* convert DER not-after time */
+ rv = DER_UTCTimeToTime(notAfter, &c->validity.notAfter);
+ if (rv) {
+ return(SECFailure);
+ }
+
+ return(SECSuccess);
+}
+
+/*
+ * Check the validity times of a certificate
+ */
+SECCertTimeValidity
+CERT_CheckCertValidTimes(CERTCertificate *c, PRTime t, PRBool allowOverride)
+{
+ PRTime notBefore, notAfter, llPendingSlop, tmp1;
+ SECStatus rv;
+
+ /* if cert is already marked OK, then don't bother to check */
+ if ( allowOverride && c->timeOK ) {
+ return(secCertTimeValid);
+ }
+
+ rv = CERT_GetCertTimes(c, &notBefore, &notAfter);
+
+ if (rv) {
+ return(secCertTimeExpired); /*XXX is this the right thing to do here?*/
+ }
+
+ LL_I2L(llPendingSlop, pendingSlop);
+ /* convert to micro seconds */
+ LL_UI2L(tmp1, PR_USEC_PER_SEC);
+ LL_MUL(llPendingSlop, llPendingSlop, tmp1);
+ LL_SUB(notBefore, notBefore, llPendingSlop);
+ if ( LL_CMP( t, <, notBefore ) ) {
+ PORT_SetError(SEC_ERROR_EXPIRED_CERTIFICATE);
+ return(secCertTimeNotValidYet);
+ }
+ if ( LL_CMP( t, >, notAfter) ) {
+ PORT_SetError(SEC_ERROR_EXPIRED_CERTIFICATE);
+ return(secCertTimeExpired);
+ }
+
+ return(secCertTimeValid);
+}
+
+SECStatus
+SEC_GetCrlTimes(CERTCrl *date, PRTime *notBefore, PRTime *notAfter)
+{
+ int rv;
+
+ /* convert DER not-before time */
+ rv = DER_UTCTimeToTime(notBefore, &date->lastUpdate);
+ if (rv) {
+ return(SECFailure);
+ }
+
+ /* convert DER not-after time */
+ if (date->nextUpdate.data) {
+ rv = DER_UTCTimeToTime(notAfter, &date->nextUpdate);
+ if (rv) {
+ return(SECFailure);
+ }
+ }
+ else {
+ LL_I2L(*notAfter, 0L);
+ }
+ return(SECSuccess);
+}
+
+/* These routines should probably be combined with the cert
+ * routines using an common extraction routine.
+ */
+SECCertTimeValidity
+SEC_CheckCrlTimes(CERTCrl *crl, PRTime t) {
+ PRTime notBefore, notAfter, llPendingSlop, tmp1;
+ SECStatus rv;
+
+ rv = SEC_GetCrlTimes(crl, &notBefore, &notAfter);
+
+ if (rv) {
+ return(secCertTimeExpired);
+ }
+
+ LL_I2L(llPendingSlop, pendingSlop);
+ /* convert to micro seconds */
+ LL_I2L(tmp1, PR_USEC_PER_SEC);
+ LL_MUL(llPendingSlop, llPendingSlop, tmp1);
+ LL_SUB(notBefore, notBefore, llPendingSlop);
+ if ( LL_CMP( t, <, notBefore ) ) {
+ return(secCertTimeNotValidYet);
+ }
+
+ /* If next update is omitted and the test for notBefore passes, then
+ we assume that the crl is up to date.
+ */
+ if ( LL_IS_ZERO(notAfter) ) {
+ return(secCertTimeValid);
+ }
+
+ if ( LL_CMP( t, >, notAfter) ) {
+ return(secCertTimeExpired);
+ }
+
+ return(secCertTimeValid);
+}
+
+PRBool
+SEC_CrlIsNewer(CERTCrl *inNew, CERTCrl *old) {
+ PRTime newNotBefore, newNotAfter;
+ PRTime oldNotBefore, oldNotAfter;
+ SECStatus rv;
+
+ /* problems with the new CRL? reject it */
+ rv = SEC_GetCrlTimes(inNew, &newNotBefore, &newNotAfter);
+ if (rv) return PR_FALSE;
+
+ /* problems with the old CRL? replace it */
+ rv = SEC_GetCrlTimes(old, &oldNotBefore, &oldNotAfter);
+ if (rv) return PR_TRUE;
+
+ /* Question: what about the notAfter's? */
+ return ((PRBool)LL_CMP(oldNotBefore, <, newNotBefore));
+}
+
+/*
+ * return required key usage and cert type based on cert usage
+ */
+SECStatus
+CERT_KeyUsageAndTypeForCertUsage(SECCertUsage usage,
+ PRBool ca,
+ unsigned int *retKeyUsage,
+ unsigned int *retCertType)
+{
+ unsigned int requiredKeyUsage = 0;
+ unsigned int requiredCertType = 0;
+
+ if ( ca ) {
+ switch ( usage ) {
+ case certUsageSSLServerWithStepUp:
+ requiredKeyUsage = KU_NS_GOVT_APPROVED | KU_KEY_CERT_SIGN;
+ requiredCertType = NS_CERT_TYPE_SSL_CA;
+ break;
+ case certUsageSSLClient:
+ requiredKeyUsage = KU_KEY_CERT_SIGN;
+ requiredCertType = NS_CERT_TYPE_SSL_CA;
+ break;
+ case certUsageSSLServer:
+ requiredKeyUsage = KU_KEY_CERT_SIGN;
+ requiredCertType = NS_CERT_TYPE_SSL_CA;
+ break;
+ case certUsageSSLCA:
+ requiredKeyUsage = KU_KEY_CERT_SIGN;
+ requiredCertType = NS_CERT_TYPE_SSL_CA;
+ break;
+ case certUsageEmailSigner:
+ requiredKeyUsage = KU_KEY_CERT_SIGN;
+ requiredCertType = NS_CERT_TYPE_EMAIL_CA;
+ break;
+ case certUsageEmailRecipient:
+ requiredKeyUsage = KU_KEY_CERT_SIGN;
+ requiredCertType = NS_CERT_TYPE_EMAIL_CA;
+ break;
+ case certUsageObjectSigner:
+ requiredKeyUsage = KU_KEY_CERT_SIGN;
+ requiredCertType = NS_CERT_TYPE_OBJECT_SIGNING_CA;
+ break;
+ case certUsageAnyCA:
+ case certUsageStatusResponder:
+ requiredKeyUsage = KU_KEY_CERT_SIGN;
+ requiredCertType = NS_CERT_TYPE_OBJECT_SIGNING_CA |
+ NS_CERT_TYPE_EMAIL_CA |
+ NS_CERT_TYPE_SSL_CA;
+ break;
+ default:
+ PORT_Assert(0);
+ goto loser;
+ }
+ } else {
+ switch ( usage ) {
+ case certUsageSSLClient:
+ requiredKeyUsage = KU_DIGITAL_SIGNATURE;
+ requiredCertType = NS_CERT_TYPE_SSL_CLIENT;
+ break;
+ case certUsageSSLServer:
+ requiredKeyUsage = KU_KEY_AGREEMENT_OR_ENCIPHERMENT;
+ requiredCertType = NS_CERT_TYPE_SSL_SERVER;
+ break;
+ case certUsageSSLServerWithStepUp:
+ requiredKeyUsage = KU_KEY_AGREEMENT_OR_ENCIPHERMENT |
+ KU_NS_GOVT_APPROVED;
+ requiredCertType = NS_CERT_TYPE_SSL_SERVER;
+ break;
+ case certUsageSSLCA:
+ requiredKeyUsage = KU_KEY_CERT_SIGN;
+ requiredCertType = NS_CERT_TYPE_SSL_CA;
+ break;
+ case certUsageEmailSigner:
+ requiredKeyUsage = KU_DIGITAL_SIGNATURE;
+ requiredCertType = NS_CERT_TYPE_EMAIL;
+ break;
+ case certUsageEmailRecipient:
+ requiredKeyUsage = KU_KEY_AGREEMENT_OR_ENCIPHERMENT;
+ requiredCertType = NS_CERT_TYPE_EMAIL;
+ break;
+ case certUsageObjectSigner:
+ requiredKeyUsage = KU_DIGITAL_SIGNATURE;
+ requiredCertType = NS_CERT_TYPE_OBJECT_SIGNING;
+ break;
+ case certUsageStatusResponder:
+ requiredKeyUsage = KU_DIGITAL_SIGNATURE;
+ requiredCertType = EXT_KEY_USAGE_STATUS_RESPONDER;
+ break;
+ default:
+ PORT_Assert(0);
+ goto loser;
+ }
+ }
+
+ if ( retKeyUsage != NULL ) {
+ *retKeyUsage = requiredKeyUsage;
+ }
+ if ( retCertType != NULL ) {
+ *retCertType = requiredCertType;
+ }
+
+ return(SECSuccess);
+loser:
+ return(SECFailure);
+}
+
+/*
+ * check the key usage of a cert against a set of required values
+ */
+SECStatus
+CERT_CheckKeyUsage(CERTCertificate *cert, unsigned int requiredUsage)
+{
+ SECKEYPublicKey *key;
+
+ /* choose between key agreement or key encipherment based on key
+ * type in cert
+ */
+ if ( requiredUsage & KU_KEY_AGREEMENT_OR_ENCIPHERMENT ) {
+ key = CERT_ExtractPublicKey(cert);
+ if (!key)
+ return SECFailure;
+ if ( ( key->keyType == keaKey ) || ( key->keyType == fortezzaKey ) ||
+ ( key->keyType == dhKey ) ) {
+ requiredUsage |= KU_KEY_AGREEMENT;
+ } else {
+ requiredUsage |= KU_KEY_ENCIPHERMENT;
+ }
+
+ /* now turn off the special bit */
+ requiredUsage &= (~KU_KEY_AGREEMENT_OR_ENCIPHERMENT);
+
+ SECKEY_DestroyPublicKey(key);
+ }
+
+ if ( ( cert->keyUsage & requiredUsage ) != requiredUsage ) {
+ return(SECFailure);
+ }
+ return(SECSuccess);
+}
+
+
+CERTCertificate *
+CERT_DupCertificate(CERTCertificate *c)
+{
+ if (c) {
+#ifdef NSS_CLASSIC
+ CERT_LockCertRefCount(c);
+ ++c->referenceCount;
+ CERT_UnlockCertRefCount(c);
+#else
+ NSSCertificate *tmp = STAN_GetNSSCertificate(c);
+ nssCertificate_AddRef(tmp);
+#endif
+ }
+ return c;
+}
+
+/*
+ * Allow use of default cert database, so that apps(such as mozilla) don't
+ * have to pass the handle all over the place.
+ */
+static CERTCertDBHandle *default_cert_db_handle = 0;
+
+void
+CERT_SetDefaultCertDB(CERTCertDBHandle *handle)
+{
+ default_cert_db_handle = handle;
+
+ return;
+}
+
+CERTCertDBHandle *
+CERT_GetDefaultCertDB(void)
+{
+ return(default_cert_db_handle);
+}
+
+/* XXX this would probably be okay/better as an xp routine? */
+static void
+sec_lower_string(char *s)
+{
+ if ( s == NULL ) {
+ return;
+ }
+
+ while ( *s ) {
+ *s = PORT_Tolower(*s);
+ s++;
+ }
+
+ return;
+}
+
+/*
+** Add a domain name to the list of names that the user has explicitly
+** allowed (despite cert name mismatches) for use with a server cert.
+*/
+SECStatus
+CERT_AddOKDomainName(CERTCertificate *cert, const char *hn)
+{
+ CERTOKDomainName *domainOK;
+ int newNameLen;
+
+ if (!hn || !(newNameLen = strlen(hn))) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ domainOK = (CERTOKDomainName *)PORT_ArenaZAlloc(cert->arena,
+ (sizeof *domainOK) + newNameLen);
+ if (!domainOK)
+ return SECFailure; /* error code is already set. */
+
+ PORT_Strcpy(domainOK->name, hn);
+ sec_lower_string(domainOK->name);
+
+ /* put at head of list. */
+ domainOK->next = cert->domainOK;
+ cert->domainOK = domainOK;
+ return SECSuccess;
+}
+
+/* returns SECSuccess if hn matches pattern cn,
+** returns SECFailure with SSL_ERROR_BAD_CERT_DOMAIN if no match,
+** returns SECFailure with some other error code if another error occurs.
+**
+** may modify cn, so caller must pass a modifiable copy.
+*/
+static SECStatus
+cert_TestHostName(char * cn, const char * hn)
+{
+ char * hndomain;
+ int regvalid;
+
+ if ((hndomain = PORT_Strchr(hn, '.')) == NULL) {
+ /* No domain in URI host name */
+ char * cndomain;
+ if ((cndomain = PORT_Strchr(cn, '.')) != NULL &&
+ (cndomain - cn) > 0) {
+ /* there is a domain in the cn string, so chop it off */
+ *cndomain = '\0';
+ }
+ }
+
+ regvalid = PORT_RegExpValid(cn);
+ if (regvalid != NON_SXP) {
+ SECStatus rv;
+ /* cn is a regular expression, try to match the shexp */
+ int match = PORT_RegExpCaseSearch(hn, cn);
+
+ if ( match == 0 ) {
+ rv = SECSuccess;
+ } else {
+ PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
+ rv = SECFailure;
+ }
+ return rv;
+ }
+ /* cn is not a regular expression */
+
+ /* compare entire hn with cert name */
+ if (PORT_Strcasecmp(hn, cn) == 0) {
+ return SECSuccess;
+ }
+
+ if ( hndomain ) {
+ /* compare just domain name with cert name */
+ if ( PORT_Strcasecmp(hndomain+1, cn) == 0 ) {
+ return SECSuccess;
+ }
+ }
+
+ PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
+ return SECFailure;
+}
+
+
+SECStatus
+cert_VerifySubjectAltName(CERTCertificate *cert, const char *hn)
+{
+ PRArenaPool * arena = NULL;
+ CERTGeneralName * nameList = NULL;
+ CERTGeneralName * current;
+ char * cn;
+ int cnBufLen;
+ unsigned int hnLen;
+ int DNSextCount = 0;
+ int IPextCount = 0;
+ PRBool isIPaddr;
+ SECStatus rv = SECFailure;
+ SECItem subAltName;
+ PRNetAddr netAddr;
+ char cnbuf[128];
+
+ subAltName.data = NULL;
+ hnLen = strlen(hn);
+ cn = cnbuf;
+ cnBufLen = sizeof cnbuf;
+
+ rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME,
+ &subAltName);
+ if (rv != SECSuccess) {
+ goto finish;
+ }
+ isIPaddr = (PR_SUCCESS == PR_StringToNetAddr(hn, &netAddr));
+ rv = SECFailure;
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (!arena)
+ goto finish;
+
+ nameList = current = CERT_DecodeAltNameExtension(arena, &subAltName);
+ if (!current)
+ goto finish;
+
+ do {
+ switch (current->type) {
+ case certDNSName:
+ if (!isIPaddr) {
+ /* DNS name current->name.other.data is not null terminated.
+ ** so must copy it.
+ */
+ int cnLen = current->name.other.len;
+ if (cnLen + 1 > cnBufLen) {
+ cnBufLen = cnLen + 1;
+ cn = (char *)PORT_ArenaAlloc(arena, cnBufLen);
+ if (!cn)
+ goto finish;
+ }
+ PORT_Memcpy(cn, current->name.other.data, cnLen);
+ cn[cnLen] = 0;
+ rv = cert_TestHostName(cn ,hn);
+ if (rv == SECSuccess)
+ goto finish;
+ }
+ DNSextCount++;
+ break;
+ case certIPAddress:
+ if (isIPaddr) {
+ int match = 0;
+ PRIPv6Addr v6Addr;
+ if (current->name.other.len == 4 && /* IP v4 address */
+ netAddr.inet.family == PR_AF_INET) {
+ match = !memcmp(&netAddr.inet.ip,
+ current->name.other.data, 4);
+ } else if (current->name.other.len == 16 && /* IP v6 address */
+ netAddr.ipv6.family == PR_AF_INET6) {
+ match = !memcmp(&netAddr.ipv6.ip,
+ current->name.other.data, 16);
+ } else if (current->name.other.len == 16 && /* IP v6 address */
+ netAddr.inet.family == PR_AF_INET) {
+ /* convert netAddr to ipv6, then compare. */
+ /* ipv4 must be in Network Byte Order on input. */
+ PR_ConvertIPv4AddrToIPv6(netAddr.inet.ip, &v6Addr);
+ match = !memcmp(&v6Addr, current->name.other.data, 16);
+ } else if (current->name.other.len == 4 && /* IP v4 address */
+ netAddr.inet.family == PR_AF_INET6) {
+ /* convert netAddr to ipv6, then compare. */
+ PRUint32 ipv4 = (current->name.other.data[0] << 24) |
+ (current->name.other.data[1] << 16) |
+ (current->name.other.data[2] << 8) |
+ current->name.other.data[3];
+ /* ipv4 must be in Network Byte Order on input. */
+ PR_ConvertIPv4AddrToIPv6(PR_htonl(ipv4), &v6Addr);
+ match = !memcmp(&netAddr.ipv6.ip, &v6Addr, 16);
+ }
+ if (match) {
+ rv = SECSuccess;
+ goto finish;
+ }
+ }
+ IPextCount++;
+ break;
+ default:
+ break;
+ }
+ current = cert_get_next_general_name(current);
+ } while (current != nameList);
+
+ if ((!isIPaddr && !DNSextCount) || (isIPaddr && !IPextCount)) {
+ /* no relevant value in the extension was found. */
+ PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
+ } else {
+ PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
+ }
+ rv = SECFailure;
+
+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 rv;
+}
+
+
+/* Make sure that the name of the host we are connecting to matches the
+ * name that is incoded in the common-name component of the certificate
+ * that they are using.
+ */
+SECStatus
+CERT_VerifyCertName(CERTCertificate *cert, const char *hn)
+{
+ char * cn;
+ SECStatus rv;
+ CERTOKDomainName *domainOK;
+
+ if (!hn || !strlen(hn)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ /* if the name is one that the user has already approved, it's OK. */
+ for (domainOK = cert->domainOK; domainOK; domainOK = domainOK->next) {
+ if (0 == PORT_Strcasecmp(hn, domainOK->name)) {
+ return SECSuccess;
+ }
+ }
+
+ /* Per RFC 2818, if the SubjectAltName extension is present, it must
+ ** be used as the cert's identity.
+ */
+ rv = cert_VerifySubjectAltName(cert, hn);
+ if (rv == SECSuccess || PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND)
+ return rv;
+
+ /* try the cert extension first, then the common name */
+ cn = CERT_FindNSStringExtension(cert, SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME);
+ if ( !cn ) {
+ cn = CERT_GetCommonName(&cert->subject);
+ }
+ if ( cn ) {
+ rv = cert_TestHostName(cn, hn);
+ PORT_Free(cn);
+ } else
+ PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
+ return rv;
+}
+
+PRBool
+CERT_CompareCerts(CERTCertificate *c1, CERTCertificate *c2)
+{
+ SECComparison comp;
+
+ comp = SECITEM_CompareItem(&c1->derCert, &c2->derCert);
+ if ( comp == SECEqual ) { /* certs are the same */
+ return(PR_TRUE);
+ } else {
+ return(PR_FALSE);
+ }
+}
+
+static SECStatus
+StringsEqual(char *s1, char *s2) {
+ if ( ( s1 == NULL ) || ( s2 == NULL ) ) {
+ if ( s1 != s2 ) { /* only one is null */
+ return(SECFailure);
+ }
+ return(SECSuccess); /* both are null */
+ }
+
+ if ( PORT_Strcmp( s1, s2 ) != 0 ) {
+ return(SECFailure); /* not equal */
+ }
+
+ return(SECSuccess); /* strings are equal */
+}
+
+
+PRBool
+CERT_CompareCertsForRedirection(CERTCertificate *c1, CERTCertificate *c2)
+{
+ SECComparison comp;
+ char *c1str, *c2str;
+ SECStatus eq;
+
+ comp = SECITEM_CompareItem(&c1->derCert, &c2->derCert);
+ if ( comp == SECEqual ) { /* certs are the same */
+ return(PR_TRUE);
+ }
+
+ /* check if they are issued by the same CA */
+ comp = SECITEM_CompareItem(&c1->derIssuer, &c2->derIssuer);
+ if ( comp != SECEqual ) { /* different issuer */
+ return(PR_FALSE);
+ }
+
+ /* check country name */
+ c1str = CERT_GetCountryName(&c1->subject);
+ c2str = CERT_GetCountryName(&c2->subject);
+ eq = StringsEqual(c1str, c2str);
+ PORT_Free(c1str);
+ PORT_Free(c2str);
+ if ( eq != SECSuccess ) {
+ return(PR_FALSE);
+ }
+
+ /* check locality name */
+ c1str = CERT_GetLocalityName(&c1->subject);
+ c2str = CERT_GetLocalityName(&c2->subject);
+ eq = StringsEqual(c1str, c2str);
+ PORT_Free(c1str);
+ PORT_Free(c2str);
+ if ( eq != SECSuccess ) {
+ return(PR_FALSE);
+ }
+
+ /* check state name */
+ c1str = CERT_GetStateName(&c1->subject);
+ c2str = CERT_GetStateName(&c2->subject);
+ eq = StringsEqual(c1str, c2str);
+ PORT_Free(c1str);
+ PORT_Free(c2str);
+ if ( eq != SECSuccess ) {
+ return(PR_FALSE);
+ }
+
+ /* check org name */
+ c1str = CERT_GetOrgName(&c1->subject);
+ c2str = CERT_GetOrgName(&c2->subject);
+ eq = StringsEqual(c1str, c2str);
+ PORT_Free(c1str);
+ PORT_Free(c2str);
+ if ( eq != SECSuccess ) {
+ return(PR_FALSE);
+ }
+
+#ifdef NOTDEF
+ /* check orgUnit name */
+ /*
+ * We need to revisit this and decide which fields should be allowed to be
+ * different
+ */
+ c1str = CERT_GetOrgUnitName(&c1->subject);
+ c2str = CERT_GetOrgUnitName(&c2->subject);
+ eq = StringsEqual(c1str, c2str);
+ PORT_Free(c1str);
+ PORT_Free(c2str);
+ if ( eq != SECSuccess ) {
+ return(PR_FALSE);
+ }
+#endif
+
+ return(PR_TRUE); /* all fields but common name are the same */
+}
+
+
+/* CERT_CertChainFromCert and CERT_DestroyCertificateList moved
+ to certhigh.c */
+
+
+CERTIssuerAndSN *
+CERT_GetCertIssuerAndSN(PRArenaPool *arena, CERTCertificate *cert)
+{
+ CERTIssuerAndSN *result;
+ SECStatus rv;
+
+ if ( arena == NULL ) {
+ arena = cert->arena;
+ }
+
+ result = (CERTIssuerAndSN*)PORT_ArenaZAlloc(arena, sizeof(*result));
+ if (result == NULL) {
+ PORT_SetError (SEC_ERROR_NO_MEMORY);
+ return NULL;
+ }
+
+ rv = SECITEM_CopyItem(arena, &result->derIssuer, &cert->derIssuer);
+ if (rv != SECSuccess)
+ return NULL;
+
+ rv = CERT_CopyName(arena, &result->issuer, &cert->issuer);
+ if (rv != SECSuccess)
+ return NULL;
+
+ rv = SECITEM_CopyItem(arena, &result->serialNumber, &cert->serialNumber);
+ if (rv != SECSuccess)
+ return NULL;
+
+ return result;
+}
+
+char *
+CERT_MakeCANickname(CERTCertificate *cert)
+{
+ char *firstname = NULL;
+ char *org = NULL;
+ char *nickname = NULL;
+ int count;
+ CERTCertificate *dummycert;
+ CERTCertDBHandle *handle;
+
+ handle = cert->dbhandle;
+
+ nickname = CERT_GetNickName(cert, handle, cert->arena);
+ if (nickname == NULL) {
+ firstname = CERT_GetCommonName(&cert->subject);
+ if ( firstname == NULL ) {
+ firstname = CERT_GetOrgUnitName(&cert->subject);
+ }
+
+ org = CERT_GetOrgName(&cert->issuer);
+ if (org == NULL) {
+ org = CERT_GetDomainComponentName(&cert->issuer);
+ if (org == NULL) {
+ if (firstname) {
+ org = firstname;
+ firstname = NULL;
+ } else {
+ org = PORT_Strdup("Unknown CA");
+ }
+ }
+ }
+
+ /* can only fail if PORT_Strdup fails, in which case
+ * we're having memory problems. */
+ if (org == NULL) {
+ goto loser;
+ }
+
+
+ count = 1;
+ while ( 1 ) {
+
+ if ( firstname ) {
+ if ( count == 1 ) {
+ nickname = PR_smprintf("%s - %s", firstname, org);
+ } else {
+ nickname = PR_smprintf("%s - %s #%d", firstname, org, count);
+ }
+ } else {
+ if ( count == 1 ) {
+ nickname = PR_smprintf("%s", org);
+ } else {
+ nickname = PR_smprintf("%s #%d", org, count);
+ }
+ }
+ if ( nickname == NULL ) {
+ goto loser;
+ }
+
+ /* look up the nickname to make sure it isn't in use already */
+ dummycert = CERT_FindCertByNickname(handle, nickname);
+
+ if ( dummycert == NULL ) {
+ goto done;
+ }
+
+ /* found a cert, destroy it and loop */
+ CERT_DestroyCertificate(dummycert);
+
+ /* free the nickname */
+ PORT_Free(nickname);
+
+ count++;
+ }
+ }
+loser:
+ if ( nickname ) {
+ PORT_Free(nickname);
+ }
+
+ nickname = "";
+
+done:
+ if ( firstname ) {
+ PORT_Free(firstname);
+ }
+ if ( org ) {
+ PORT_Free(org);
+ }
+
+ return(nickname);
+}
+
+/* CERT_Import_CAChain moved to certhigh.c */
+
+void
+CERT_DestroyCrl (CERTSignedCrl *crl)
+{
+ SEC_DestroyCrl (crl);
+}
+
+
+
+/*
+ * Does a cert belong to a CA? We decide based on perm database trust
+ * flags, Netscape Cert Type Extension, and KeyUsage Extension.
+ */
+PRBool
+CERT_IsCACert(CERTCertificate *cert, unsigned int *rettype)
+{
+ CERTCertTrust *trust;
+ SECStatus rv;
+ unsigned int type;
+ PRBool ret;
+
+ ret = PR_FALSE;
+ type = 0;
+
+ if ( cert->trust && (cert->trust->sslFlags|cert->trust->emailFlags|
+ cert->trust->objectSigningFlags)) {
+ trust = cert->trust;
+ if ( ( ( trust->sslFlags & CERTDB_VALID_CA ) == CERTDB_VALID_CA ) ||
+ ( ( trust->sslFlags & CERTDB_TRUSTED_CA ) == CERTDB_TRUSTED_CA ) ) {
+ ret = PR_TRUE;
+ type |= NS_CERT_TYPE_SSL_CA;
+ }
+
+ if ( ( ( trust->emailFlags & CERTDB_VALID_CA ) == CERTDB_VALID_CA ) ||
+ ( ( trust->emailFlags & CERTDB_TRUSTED_CA ) == CERTDB_TRUSTED_CA ) ) {
+ ret = PR_TRUE;
+ type |= NS_CERT_TYPE_EMAIL_CA;
+ }
+
+ if ( ( ( trust->objectSigningFlags & CERTDB_VALID_CA )
+ == CERTDB_VALID_CA ) ||
+ ( ( trust->objectSigningFlags & CERTDB_TRUSTED_CA )
+ == CERTDB_TRUSTED_CA ) ) {
+ ret = PR_TRUE;
+ type |= NS_CERT_TYPE_OBJECT_SIGNING_CA;
+ }
+ } else {
+ if ( cert->nsCertType &
+ ( NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA |
+ NS_CERT_TYPE_OBJECT_SIGNING_CA ) ) {
+ ret = PR_TRUE;
+ type = (cert->nsCertType & NS_CERT_TYPE_CA);
+ } else {
+ CERTBasicConstraints constraints;
+ rv = CERT_FindBasicConstraintExten(cert, &constraints);
+ if ( rv == SECSuccess ) {
+ if ( constraints.isCA ) {
+ ret = PR_TRUE;
+ type = (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA);
+ }
+ }
+ }
+
+ /* finally check if it's a FORTEZZA V1 CA */
+ if (ret == PR_FALSE) {
+ if (fortezzaIsCA(cert)) {
+ ret = PR_TRUE;
+ type = (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA);
+ }
+ }
+ }
+
+ /* the isRoot flag trumps all */
+ if (cert->isRoot) {
+ ret = PR_TRUE;
+ /* set only these by default, same as above */
+ type = (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA);
+ }
+
+ if ( rettype != NULL ) {
+ *rettype = type;
+ }
+
+ return(ret);
+}
+
+PRBool
+CERT_IsCADERCert(SECItem *derCert, unsigned int *type) {
+ CERTCertificate *cert;
+ PRBool isCA;
+
+ /* This is okay -- only looks at extensions */
+ cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
+ if (cert == NULL) return PR_FALSE;
+
+ isCA = CERT_IsCACert(cert,type);
+ CERT_DestroyCertificate (cert);
+ return isCA;
+}
+
+PRBool
+CERT_IsRootDERCert(SECItem *derCert)
+{
+ CERTCertificate *cert;
+ PRBool isRoot;
+
+ /* This is okay -- only looks at extensions */
+ cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
+ if (cert == NULL) return PR_FALSE;
+
+ isRoot = cert->isRoot;
+ CERT_DestroyCertificate (cert);
+ return isRoot;
+}
+
+
+/*
+ * is certa newer than certb? If one is expired, pick the other one.
+ */
+PRBool
+CERT_IsNewer(CERTCertificate *certa, CERTCertificate *certb)
+{
+ PRTime notBeforeA, notAfterA, notBeforeB, notAfterB, now;
+ SECStatus rv;
+ PRBool newerbefore, newerafter;
+
+ rv = CERT_GetCertTimes(certa, &notBeforeA, &notAfterA);
+ if ( rv != SECSuccess ) {
+ return(PR_FALSE);
+ }
+
+ rv = CERT_GetCertTimes(certb, &notBeforeB, &notAfterB);
+ if ( rv != SECSuccess ) {
+ return(PR_TRUE);
+ }
+
+ newerbefore = PR_FALSE;
+ if ( LL_CMP(notBeforeA, >, notBeforeB) ) {
+ newerbefore = PR_TRUE;
+ }
+
+ newerafter = PR_FALSE;
+ if ( LL_CMP(notAfterA, >, notAfterB) ) {
+ newerafter = PR_TRUE;
+ }
+
+ if ( newerbefore && newerafter ) {
+ return(PR_TRUE);
+ }
+
+ if ( ( !newerbefore ) && ( !newerafter ) ) {
+ return(PR_FALSE);
+ }
+
+ /* get current UTC time */
+ now = PR_Now();
+
+ if ( newerbefore ) {
+ /* cert A was issued after cert B, but expires sooner */
+ /* if A is expired, then pick B */
+ if ( LL_CMP(notAfterA, <, now ) ) {
+ return(PR_FALSE);
+ }
+ return(PR_TRUE);
+ } else {
+ /* cert B was issued after cert A, but expires sooner */
+ /* if B is expired, then pick A */
+ if ( LL_CMP(notAfterB, <, now ) ) {
+ return(PR_TRUE);
+ }
+ return(PR_FALSE);
+ }
+}
+
+void
+CERT_DestroyCertArray(CERTCertificate **certs, unsigned int ncerts)
+{
+ unsigned int i;
+
+ if ( certs ) {
+ for ( i = 0; i < ncerts; i++ ) {
+ if ( certs[i] ) {
+ CERT_DestroyCertificate(certs[i]);
+ }
+ }
+
+ PORT_Free(certs);
+ }
+
+ return;
+}
+
+char *
+CERT_FixupEmailAddr(char *emailAddr)
+{
+ char *retaddr;
+ char *str;
+
+ if ( emailAddr == NULL ) {
+ return(NULL);
+ }
+
+ /* copy the string */
+ str = retaddr = PORT_Strdup(emailAddr);
+ if ( str == NULL ) {
+ return(NULL);
+ }
+
+ /* make it lower case */
+ while ( *str ) {
+ *str = tolower( *str );
+ str++;
+ }
+
+ return(retaddr);
+}
+
+/*
+ * NOTE - don't allow encode of govt-approved or invisible bits
+ */
+SECStatus
+CERT_DecodeTrustString(CERTCertTrust *trust, char *trusts)
+{
+ unsigned int i;
+ unsigned int *pflags;
+
+ trust->sslFlags = 0;
+ trust->emailFlags = 0;
+ trust->objectSigningFlags = 0;
+
+ pflags = &trust->sslFlags;
+
+ for (i=0; i < PORT_Strlen(trusts); i++) {
+ switch (trusts[i]) {
+ case 'p':
+ *pflags = *pflags | CERTDB_VALID_PEER;
+ break;
+
+ case 'P':
+ *pflags = *pflags | CERTDB_TRUSTED | CERTDB_VALID_PEER;
+ break;
+
+ case 'w':
+ *pflags = *pflags | CERTDB_SEND_WARN;
+ break;
+
+ case 'c':
+ *pflags = *pflags | CERTDB_VALID_CA;
+ break;
+
+ case 'T':
+ *pflags = *pflags | CERTDB_TRUSTED_CLIENT_CA | CERTDB_VALID_CA;
+ break;
+
+ case 'C' :
+ *pflags = *pflags | CERTDB_TRUSTED_CA | CERTDB_VALID_CA;
+ break;
+
+ case 'u':
+ *pflags = *pflags | CERTDB_USER;
+ break;
+
+#ifdef DEBUG_NSSTEAM_ONLY
+ case 'i':
+ *pflags = *pflags | CERTDB_INVISIBLE_CA;
+ break;
+ case 'g':
+ *pflags = *pflags | CERTDB_GOVT_APPROVED_CA;
+ break;
+#endif /* DEBUG_NSSTEAM_ONLY */
+
+ case ',':
+ if ( pflags == &trust->sslFlags ) {
+ pflags = &trust->emailFlags;
+ } else {
+ pflags = &trust->objectSigningFlags;
+ }
+ break;
+ default:
+ return SECFailure;
+ }
+ }
+
+ return SECSuccess;
+}
+
+static void
+EncodeFlags(char *trusts, unsigned int flags)
+{
+ if (flags & CERTDB_VALID_CA)
+ if (!(flags & CERTDB_TRUSTED_CA) &&
+ !(flags & CERTDB_TRUSTED_CLIENT_CA))
+ PORT_Strcat(trusts, "c");
+ if (flags & CERTDB_VALID_PEER)
+ if (!(flags & CERTDB_TRUSTED))
+ PORT_Strcat(trusts, "p");
+ if (flags & CERTDB_TRUSTED_CA)
+ PORT_Strcat(trusts, "C");
+ if (flags & CERTDB_TRUSTED_CLIENT_CA)
+ PORT_Strcat(trusts, "T");
+ if (flags & CERTDB_TRUSTED)
+ PORT_Strcat(trusts, "P");
+ if (flags & CERTDB_USER)
+ PORT_Strcat(trusts, "u");
+ if (flags & CERTDB_SEND_WARN)
+ PORT_Strcat(trusts, "w");
+ if (flags & CERTDB_INVISIBLE_CA)
+ PORT_Strcat(trusts, "I");
+ if (flags & CERTDB_GOVT_APPROVED_CA)
+ PORT_Strcat(trusts, "G");
+ return;
+}
+
+char *
+CERT_EncodeTrustString(CERTCertTrust *trust)
+{
+ char tmpTrustSSL[32];
+ char tmpTrustEmail[32];
+ char tmpTrustSigning[32];
+ char *retstr = NULL;
+
+ if ( trust ) {
+ tmpTrustSSL[0] = '\0';
+ tmpTrustEmail[0] = '\0';
+ tmpTrustSigning[0] = '\0';
+
+ EncodeFlags(tmpTrustSSL, trust->sslFlags);
+ EncodeFlags(tmpTrustEmail, trust->emailFlags);
+ EncodeFlags(tmpTrustSigning, trust->objectSigningFlags);
+
+ retstr = PR_smprintf("%s,%s,%s", tmpTrustSSL, tmpTrustEmail,
+ tmpTrustSigning);
+ }
+
+ return(retstr);
+}
+
+/* in 3.4, this will only set trust */
+SECStatus
+CERT_SaveImportedCert(CERTCertificate *cert, SECCertUsage usage,
+ PRBool caOnly, char *nickname)
+{
+ SECStatus rv;
+ PRBool saveit;
+ CERTCertTrust trust;
+ PRBool isCA;
+ unsigned int certtype;
+
+ isCA = CERT_IsCACert(cert, NULL);
+ if ( caOnly && ( !isCA ) ) {
+ return(SECSuccess);
+ }
+ /* In NSS 3.4, certs are given zero trust upon import. However, this
+ * function needs to set up default CA trust (CERTDB_VALID_CA), or
+ * PKCS#12 imported certs will not show up correctly. In the case of a
+ * CA cert with zero trust, continue with this function. But if the cert
+ * does already have some trust bits, exit and do not change them.
+ */
+ if (isCA && cert->trust &&
+ (cert->trust->sslFlags |
+ cert->trust->emailFlags |
+ cert->trust->objectSigningFlags)) {
+ return(SECSuccess);
+ }
+
+ saveit = PR_TRUE;
+
+ PORT_Memset((void *)&trust, 0, sizeof(trust));
+
+ certtype = cert->nsCertType;
+
+ /* if no CA bits in cert type, then set all CA bits */
+ if ( isCA && ( ! ( certtype & NS_CERT_TYPE_CA ) ) ) {
+ certtype |= NS_CERT_TYPE_CA;
+ }
+
+ /* if no app bits in cert type, then set all app bits */
+ if ( ( !isCA ) && ( ! ( certtype & NS_CERT_TYPE_APP ) ) ) {
+ certtype |= NS_CERT_TYPE_APP;
+ }
+
+ switch ( usage ) {
+ case certUsageEmailSigner:
+ case certUsageEmailRecipient:
+ if ( isCA ) {
+ if ( certtype & NS_CERT_TYPE_EMAIL_CA ) {
+ trust.emailFlags = CERTDB_VALID_CA;
+ }
+ } else {
+ if ( cert->emailAddr == NULL ) {
+ saveit = PR_FALSE;
+ }
+
+ if ( certtype & NS_CERT_TYPE_EMAIL ) {
+ trust.emailFlags = CERTDB_VALID_PEER;
+ if ( ! ( cert->rawKeyUsage & KU_KEY_ENCIPHERMENT ) ) {
+ /* don't save it if KeyEncipherment is not allowed */
+ saveit = PR_FALSE;
+ }
+ }
+ }
+ break;
+ case certUsageUserCertImport:
+ if ( isCA ) {
+ if ( certtype & NS_CERT_TYPE_SSL_CA ) {
+ trust.sslFlags = CERTDB_VALID_CA;
+ }
+
+ if ( certtype & NS_CERT_TYPE_EMAIL_CA ) {
+ trust.emailFlags = CERTDB_VALID_CA;
+ }
+
+ if ( certtype & NS_CERT_TYPE_OBJECT_SIGNING_CA ) {
+ trust.objectSigningFlags = CERTDB_VALID_CA;
+ }
+
+ } else {
+ if ( certtype & NS_CERT_TYPE_SSL_CLIENT ) {
+ trust.sslFlags = CERTDB_VALID_PEER;
+ }
+
+ if ( certtype & NS_CERT_TYPE_EMAIL ) {
+ trust.emailFlags = CERTDB_VALID_PEER;
+ }
+
+ if ( certtype & NS_CERT_TYPE_OBJECT_SIGNING ) {
+ trust.objectSigningFlags = CERTDB_VALID_PEER;
+ }
+ }
+ break;
+ case certUsageAnyCA:
+ trust.sslFlags = CERTDB_VALID_CA;
+ break;
+ case certUsageSSLCA:
+ trust.sslFlags = CERTDB_VALID_CA |
+ CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA;
+ break;
+ default: /* XXX added to quiet warnings; no other cases needed? */
+ break;
+ }
+
+ if ( saveit ) {
+ rv = CERT_ChangeCertTrust(cert->dbhandle, cert, &trust);
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+ }
+
+ rv = SECSuccess;
+ goto done;
+
+loser:
+ rv = SECFailure;
+done:
+
+ return(rv);
+}
+
+SECStatus
+CERT_ImportCerts(CERTCertDBHandle *certdb, SECCertUsage usage,
+ unsigned int ncerts, SECItem **derCerts,
+ CERTCertificate ***retCerts, PRBool keepCerts,
+ PRBool caOnly, char *nickname)
+{
+ unsigned int i;
+ CERTCertificate **certs = NULL;
+ SECStatus rv;
+ unsigned int fcerts = 0;
+
+ if ( ncerts ) {
+ certs = (CERTCertificate**)PORT_ZAlloc(sizeof(CERTCertificate *) * ncerts );
+ if ( certs == NULL ) {
+ return(SECFailure);
+ }
+
+ /* decode all of the certs into the temporary DB */
+ for ( i = 0, fcerts= 0; i < ncerts; i++) {
+ certs[fcerts] = CERT_NewTempCertificate(certdb,
+ derCerts[i],
+ NULL,
+ PR_FALSE,
+ PR_TRUE);
+ if (certs[fcerts]) fcerts++;
+ }
+
+ if ( keepCerts ) {
+ for ( i = 0; i < fcerts; i++ ) {
+ char* canickname = NULL;
+ PRBool freeNickname = PR_FALSE;
+
+ SECKEY_UpdateCertPQG(certs[i]);
+
+ if ( CERT_IsCACert(certs[i], NULL) ) {
+ canickname = CERT_MakeCANickname(certs[i]);
+ if ( canickname != NULL ) {
+ freeNickname = PR_TRUE;
+ }
+ }
+
+ if(CERT_IsCACert(certs[i], NULL) && (fcerts > 1)) {
+ /* if we are importing only a single cert and specifying
+ * a nickname, we want to use that nickname if it a CA,
+ * otherwise if there are more than one cert, we don't
+ * know which cert it belongs to. But we still may try
+ * the individual canickname from the cert itself.
+ */
+ rv = CERT_AddTempCertToPerm(certs[i], canickname, NULL);
+ } else {
+ rv = CERT_AddTempCertToPerm(certs[i],
+ nickname?nickname:canickname, NULL);
+ }
+ if (rv == SECSuccess) {
+ CERT_SaveImportedCert(certs[i], usage, caOnly, NULL);
+ }
+
+ if (PR_TRUE == freeNickname) {
+ PORT_Free(canickname);
+ }
+ /* don't care if it fails - keep going */
+ }
+ }
+ }
+
+ if ( retCerts ) {
+ *retCerts = certs;
+ } else {
+ if (certs) {
+ CERT_DestroyCertArray(certs, fcerts);
+ }
+ }
+
+ return(SECSuccess);
+
+#if 0 /* dead code here - why ?? XXX */
+loser:
+ if ( retCerts ) {
+ *retCerts = NULL;
+ }
+ if ( certs ) {
+ CERT_DestroyCertArray(certs, ncerts);
+ }
+ return(SECFailure);
+#endif
+}
+
+/*
+ * a real list of certificates - need to convert CERTCertificateList
+ * stuff and ASN 1 encoder/decoder over to using this...
+ */
+CERTCertList *
+CERT_NewCertList(void)
+{
+ PRArenaPool *arena = NULL;
+ CERTCertList *ret = NULL;
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if ( arena == NULL ) {
+ goto loser;
+ }
+
+ ret = (CERTCertList *)PORT_ArenaZAlloc(arena, sizeof(CERTCertList));
+ if ( ret == NULL ) {
+ goto loser;
+ }
+
+ ret->arena = arena;
+
+ PR_INIT_CLIST(&ret->list);
+
+ return(ret);
+
+loser:
+ if ( arena != NULL ) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ return(NULL);
+}
+
+void
+CERT_DestroyCertList(CERTCertList *certs)
+{
+ PRCList *node;
+
+ while( !PR_CLIST_IS_EMPTY(&certs->list) ) {
+ node = PR_LIST_HEAD(&certs->list);
+ CERT_DestroyCertificate(((CERTCertListNode *)node)->cert);
+ PR_REMOVE_LINK(node);
+ }
+
+ PORT_FreeArena(certs->arena, PR_FALSE);
+
+ return;
+}
+
+void
+CERT_RemoveCertListNode(CERTCertListNode *node)
+{
+ CERT_DestroyCertificate(node->cert);
+ PR_REMOVE_LINK(&node->links);
+ return;
+}
+
+
+SECStatus
+CERT_AddCertToListTailWithData(CERTCertList *certs,
+ CERTCertificate *cert, void *appData)
+{
+ CERTCertListNode *node;
+
+ node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena,
+ sizeof(CERTCertListNode));
+ if ( node == NULL ) {
+ goto loser;
+ }
+
+ PR_INSERT_BEFORE(&node->links, &certs->list);
+ /* certs->count++; */
+ node->cert = cert;
+ node->appData = appData;
+ return(SECSuccess);
+
+loser:
+ return(SECFailure);
+}
+
+SECStatus
+CERT_AddCertToListTail(CERTCertList *certs, CERTCertificate *cert)
+{
+ return CERT_AddCertToListTailWithData(certs, cert, NULL);
+}
+
+SECStatus
+CERT_AddCertToListHeadWithData(CERTCertList *certs,
+ CERTCertificate *cert, void *appData)
+{
+ CERTCertListNode *node;
+ CERTCertListNode *head;
+
+ head = CERT_LIST_HEAD(certs);
+
+ if (head == NULL) return CERT_AddCertToListTail(certs,cert);
+
+ node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena,
+ sizeof(CERTCertListNode));
+ if ( node == NULL ) {
+ goto loser;
+ }
+
+ PR_INSERT_BEFORE(&node->links, &head->links);
+ /* certs->count++; */
+ node->cert = cert;
+ node->appData = appData;
+ return(SECSuccess);
+
+loser:
+ return(SECFailure);
+}
+
+SECStatus
+CERT_AddCertToListHead(CERTCertList *certs, CERTCertificate *cert)
+{
+ return CERT_AddCertToListHeadWithData(certs, cert, NULL);
+}
+
+/*
+ * Sort callback function to determine if cert a is newer than cert b.
+ * Not valid certs are considered older than valid certs.
+ */
+PRBool
+CERT_SortCBValidity(CERTCertificate *certa,
+ CERTCertificate *certb,
+ void *arg)
+{
+ PRTime sorttime;
+ PRTime notBeforeA, notAfterA, notBeforeB, notAfterB;
+ SECStatus rv;
+ PRBool newerbefore, newerafter;
+ PRBool aNotValid = PR_FALSE, bNotValid = PR_FALSE;
+
+ sorttime = *(PRTime *)arg;
+
+ rv = CERT_GetCertTimes(certa, &notBeforeA, &notAfterA);
+ if ( rv != SECSuccess ) {
+ return(PR_FALSE);
+ }
+
+ rv = CERT_GetCertTimes(certb, &notBeforeB, &notAfterB);
+ if ( rv != SECSuccess ) {
+ return(PR_TRUE);
+ }
+ newerbefore = PR_FALSE;
+ if ( LL_CMP(notBeforeA, >, notBeforeB) ) {
+ newerbefore = PR_TRUE;
+ }
+ newerafter = PR_FALSE;
+ if ( LL_CMP(notAfterA, >, notAfterB) ) {
+ newerafter = PR_TRUE;
+ }
+
+ /* check if A is valid at sorttime */
+ if ( CERT_CheckCertValidTimes(certa, sorttime, PR_FALSE)
+ != secCertTimeValid ) {
+ aNotValid = PR_TRUE;
+ }
+
+ /* check if B is valid at sorttime */
+ if ( CERT_CheckCertValidTimes(certb, sorttime, PR_FALSE)
+ != secCertTimeValid ) {
+ bNotValid = PR_TRUE;
+ }
+
+ /* a is valid, b is not */
+ if ( bNotValid && ( ! aNotValid ) ) {
+ return(PR_TRUE);
+ }
+
+ /* b is valid, a is not */
+ if ( aNotValid && ( ! bNotValid ) ) {
+ return(PR_FALSE);
+ }
+
+ /* a and b are either valid or not valid */
+ if ( newerbefore && newerafter ) {
+ return(PR_TRUE);
+ }
+
+ if ( ( !newerbefore ) && ( !newerafter ) ) {
+ return(PR_FALSE);
+ }
+
+ if ( newerbefore ) {
+ /* cert A was issued after cert B, but expires sooner */
+ return(PR_TRUE);
+ } else {
+ /* cert B was issued after cert A, but expires sooner */
+ return(PR_FALSE);
+ }
+}
+
+
+SECStatus
+CERT_AddCertToListSorted(CERTCertList *certs,
+ CERTCertificate *cert,
+ CERTSortCallback f,
+ void *arg)
+{
+ CERTCertListNode *node;
+ CERTCertListNode *head;
+ PRBool ret;
+
+ node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena,
+ sizeof(CERTCertListNode));
+ if ( node == NULL ) {
+ goto loser;
+ }
+
+ head = CERT_LIST_HEAD(certs);
+
+ while ( !CERT_LIST_END(head, certs) ) {
+
+ /* if cert is already in the list, then don't add it again */
+ if ( cert == head->cert ) {
+ /*XXX*/
+ /* don't keep a reference */
+ CERT_DestroyCertificate(cert);
+ goto done;
+ }
+
+ ret = (* f)(cert, head->cert, arg);
+ /* if sort function succeeds, then insert before current node */
+ if ( ret ) {
+ PR_INSERT_BEFORE(&node->links, &head->links);
+ goto done;
+ }
+
+ head = CERT_LIST_NEXT(head);
+ }
+ /* if we get to the end, then just insert it at the tail */
+ PR_INSERT_BEFORE(&node->links, &certs->list);
+
+done:
+ /* certs->count++; */
+ node->cert = cert;
+ return(SECSuccess);
+
+loser:
+ return(SECFailure);
+}
+
+/* This routine is here because pcertdb.c still has a call to it.
+ * The SMIME profile code in pcertdb.c should be split into high (find
+ * the email cert) and low (store the profile) code. At that point, we
+ * can move this to certhigh.c where it belongs.
+ *
+ * remove certs from a list that don't have keyUsage and certType
+ * that match the given usage.
+ */
+SECStatus
+CERT_FilterCertListByUsage(CERTCertList *certList, SECCertUsage usage,
+ PRBool ca)
+{
+ unsigned int requiredKeyUsage;
+ unsigned int requiredCertType;
+ CERTCertListNode *node, *savenode;
+ PRBool bad;
+ SECStatus rv;
+ unsigned int certType;
+ PRBool dummyret;
+
+ if (certList == NULL) goto loser;
+
+ rv = CERT_KeyUsageAndTypeForCertUsage(usage, ca, &requiredKeyUsage,
+ &requiredCertType);
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ node = CERT_LIST_HEAD(certList);
+
+ while ( !CERT_LIST_END(node, certList) ) {
+
+ bad = PR_FALSE;
+
+ /* bad key usage */
+ if ( CERT_CheckKeyUsage(node->cert, requiredKeyUsage )
+ != SECSuccess ) {
+ bad = PR_TRUE;
+ }
+ /* bad cert type */
+ if ( ca ) {
+ /* This function returns a more comprehensive cert type that
+ * takes trust flags into consideration. Should probably
+ * fix the cert decoding code to do this.
+ */
+ dummyret = CERT_IsCACert(node->cert, &certType);
+ } else {
+ certType = node->cert->nsCertType;
+ }
+
+ if ( ! ( certType & requiredCertType ) ) {
+ bad = PR_TRUE;
+ }
+
+ if ( bad ) {
+ /* remove the node if it is bad */
+ savenode = CERT_LIST_NEXT(node);
+ CERT_RemoveCertListNode(node);
+ node = savenode;
+ } else {
+ node = CERT_LIST_NEXT(node);
+ }
+ }
+ return(SECSuccess);
+
+loser:
+ return(SECFailure);
+}
+
+PRBool CERT_IsUserCert(CERTCertificate* cert)
+{
+ if ( (cert->trust->sslFlags & CERTDB_USER ) ||
+ (cert->trust->emailFlags & CERTDB_USER ) ||
+ (cert->trust->objectSigningFlags & CERTDB_USER ) ) {
+ return PR_TRUE;
+ } else {
+ return PR_FALSE;
+ }
+}
+
+SECStatus
+CERT_FilterCertListForUserCerts(CERTCertList *certList)
+{
+ CERTCertListNode *node, *freenode;
+ CERTCertificate *cert;
+
+ if (!certList) {
+ return SECFailure;
+ }
+
+ node = CERT_LIST_HEAD(certList);
+
+ while ( ! CERT_LIST_END(node, certList) ) {
+ cert = node->cert;
+ if ( PR_TRUE != CERT_IsUserCert(cert) ) {
+ /* Not a User Cert, so remove this cert from the list */
+ freenode = node;
+ node = CERT_LIST_NEXT(node);
+ CERT_RemoveCertListNode(freenode);
+ } else {
+ /* Is a User cert, so leave it in the list */
+ node = CERT_LIST_NEXT(node);
+ }
+ }
+
+ return(SECSuccess);
+}
+
+static PZLock *certRefCountLock = NULL;
+
+/*
+ * Acquire the cert reference count lock
+ * There is currently one global lock for all certs, but I'm putting a cert
+ * arg here so that it will be easy to make it per-cert in the future if
+ * that turns out to be necessary.
+ */
+void
+CERT_LockCertRefCount(CERTCertificate *cert)
+{
+ if ( certRefCountLock == NULL ) {
+ nss_InitLock(&certRefCountLock, nssILockRefLock);
+ PORT_Assert(certRefCountLock != NULL);
+ }
+
+ PZ_Lock(certRefCountLock);
+ return;
+}
+
+/*
+ * Free the cert reference count lock
+ */
+void
+CERT_UnlockCertRefCount(CERTCertificate *cert)
+{
+ PRStatus prstat;
+
+ PORT_Assert(certRefCountLock != NULL);
+
+ prstat = PZ_Unlock(certRefCountLock);
+
+ PORT_Assert(prstat == PR_SUCCESS);
+
+ return;
+}
+
+static PZLock *certTrustLock = NULL;
+
+/*
+ * Acquire the cert trust lock
+ * There is currently one global lock for all certs, but I'm putting a cert
+ * arg here so that it will be easy to make it per-cert in the future if
+ * that turns out to be necessary.
+ */
+void
+CERT_LockCertTrust(CERTCertificate *cert)
+{
+ if ( certTrustLock == NULL ) {
+ nss_InitLock(&certTrustLock, nssILockCertDB);
+ PORT_Assert(certTrustLock != NULL);
+ }
+
+ PZ_Lock(certTrustLock);
+ return;
+}
+
+/*
+ * Free the cert trust lock
+ */
+void
+CERT_UnlockCertTrust(CERTCertificate *cert)
+{
+ PRStatus prstat;
+
+ PORT_Assert(certTrustLock != NULL);
+
+ prstat = PZ_Unlock(certTrustLock);
+
+ PORT_Assert(prstat == PR_SUCCESS);
+
+ return;
+}
+
+
+/*
+ * Get the StatusConfig data for this handle
+ */
+CERTStatusConfig *
+CERT_GetStatusConfig(CERTCertDBHandle *handle)
+{
+ return handle->statusConfig;
+}
+
+/*
+ * Set the StatusConfig data for this handle. There
+ * should not be another configuration set.
+ */
+void
+CERT_SetStatusConfig(CERTCertDBHandle *handle, CERTStatusConfig *statusConfig)
+{
+ PORT_Assert(handle->statusConfig == NULL);
+ handle->statusConfig = statusConfig;
+}
+
+/*
+ * Code for dealing with subjKeyID to cert mappings.
+ */
+
+static PLHashTable *gSubjKeyIDHash = NULL;
+static PRLock *gSubjKeyIDLock = NULL;
+
+static void *cert_AllocTable(void *pool, PRSize size)
+{
+ return PORT_Alloc(size);
+}
+
+static void cert_FreeTable(void *pool, void *item)
+{
+ PORT_Free(item);
+}
+
+static PLHashEntry* cert_AllocEntry(void *pool, const void *key)
+{
+ return PORT_New(PLHashEntry);
+}
+
+static void cert_FreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
+{
+ SECITEM_FreeItem((SECItem*)(he->value), PR_TRUE);
+ if (flag == HT_FREE_ENTRY) {
+ SECITEM_FreeItem((SECItem*)(he->key), PR_TRUE);
+ PORT_Free(he);
+ }
+}
+
+static PLHashAllocOps cert_AllocOps = {
+ cert_AllocTable, cert_FreeTable, cert_AllocEntry, cert_FreeEntry
+};
+
+SECStatus
+cert_CreateSubjectKeyIDHashTable(void)
+{
+ gSubjKeyIDHash = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
+ SECITEM_HashCompare,
+ &cert_AllocOps, NULL);
+ if (!gSubjKeyIDHash) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return SECFailure;
+ }
+ gSubjKeyIDLock = PR_NewLock();
+ if (!gSubjKeyIDLock) {
+ PL_HashTableDestroy(gSubjKeyIDHash);
+ gSubjKeyIDHash = NULL;
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return SECFailure;
+ }
+ return SECSuccess;
+
+}
+
+SECStatus
+cert_AddSubjectKeyIDMapping(SECItem *subjKeyID, CERTCertificate *cert)
+{
+ SECItem *newKeyID, *oldVal, *newVal;
+ SECStatus rv = SECFailure;
+
+ if (!gSubjKeyIDLock) {
+ /* If one is created, then both are there. So only check for one. */
+ return SECFailure;
+ }
+
+ newVal = SECITEM_DupItem(&cert->derCert);
+ if (!newVal) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ goto done;
+ }
+ newKeyID = SECITEM_DupItem(subjKeyID);
+ if (!newKeyID) {
+ SECITEM_FreeItem(newVal, PR_TRUE);
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ goto done;
+ }
+
+ PR_Lock(gSubjKeyIDLock);
+ /* The hash table implementation does not free up the memory
+ * associated with the key of an already existing entry if we add a
+ * duplicate, so we would wind up leaking the previously allocated
+ * key if we don't remove before adding.
+ */
+ oldVal = (SECItem*)PL_HashTableLookup(gSubjKeyIDHash, subjKeyID);
+ if (oldVal) {
+ PL_HashTableRemove(gSubjKeyIDHash, subjKeyID);
+ }
+
+ rv = (PL_HashTableAdd(gSubjKeyIDHash, newKeyID, newVal)) ? SECSuccess :
+ SECFailure;
+ PR_Unlock(gSubjKeyIDLock);
+done:
+ return rv;
+}
+
+SECStatus
+cert_RemoveSubjectKeyIDMapping(SECItem *subjKeyID)
+{
+ SECStatus rv;
+ if (!gSubjKeyIDLock)
+ return SECFailure;
+
+ PR_Lock(gSubjKeyIDLock);
+ rv = (PL_HashTableRemove(gSubjKeyIDHash, subjKeyID)) ? SECSuccess :
+ SECFailure;
+ PR_Unlock(gSubjKeyIDLock);
+ return rv;
+}
+
+SECStatus
+cert_DestroySubjectKeyIDHashTable(void)
+{
+ if (gSubjKeyIDHash) {
+ PR_Lock(gSubjKeyIDLock);
+ PL_HashTableDestroy(gSubjKeyIDHash);
+ gSubjKeyIDHash = NULL;
+ PR_Unlock(gSubjKeyIDLock);
+ PR_DestroyLock(gSubjKeyIDLock);
+ gSubjKeyIDLock = NULL;
+ }
+ return SECSuccess;
+}
+
+SECItem*
+cert_FindDERCertBySubjectKeyID(SECItem *subjKeyID)
+{
+ SECItem *val;
+
+ if (!gSubjKeyIDLock)
+ return NULL;
+
+ PR_Lock(gSubjKeyIDLock);
+ val = (SECItem*)PL_HashTableLookup(gSubjKeyIDHash, subjKeyID);
+ if (val) {
+ val = SECITEM_DupItem(val);
+ }
+ PR_Unlock(gSubjKeyIDLock);
+ return val;
+}
+
+CERTCertificate*
+CERT_FindCertBySubjectKeyID(CERTCertDBHandle *handle, SECItem *subjKeyID)
+{
+ CERTCertificate *cert = NULL;
+ SECItem *derCert;
+
+ derCert = cert_FindDERCertBySubjectKeyID(subjKeyID);
+ if (derCert) {
+ cert = CERT_FindCertByDERCert(handle, derCert);
+ SECITEM_FreeItem(derCert, PR_TRUE);
+ }
+ return cert;
+}
diff --git a/security/nss/lib/certdb/certdb.h b/security/nss/lib/certdb/certdb.h
new file mode 100644
index 000000000..7340961c2
--- /dev/null
+++ b/security/nss/lib/certdb/certdb.h
@@ -0,0 +1,159 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+#ifndef _CERTDB_H_
+#define _CERTDB_H_
+
+
+/* common flags for all types of certificates */
+#define CERTDB_VALID_PEER (1<<0)
+#define CERTDB_TRUSTED (1<<1)
+#define CERTDB_SEND_WARN (1<<2)
+#define CERTDB_VALID_CA (1<<3)
+#define CERTDB_TRUSTED_CA (1<<4) /* trusted for issuing server certs */
+#define CERTDB_NS_TRUSTED_CA (1<<5)
+#define CERTDB_USER (1<<6)
+#define CERTDB_TRUSTED_CLIENT_CA (1<<7) /* trusted for issuing client certs */
+#define CERTDB_INVISIBLE_CA (1<<8) /* don't show in UI */
+#define CERTDB_GOVT_APPROVED_CA (1<<9) /* can do strong crypto in export ver */
+
+
+SEC_BEGIN_PROTOS
+
+CERTSignedCrl *
+SEC_FindCrlByKey(CERTCertDBHandle *handle, SECItem *crlKey, int type);
+
+CERTSignedCrl *
+SEC_FindCrlByName(CERTCertDBHandle *handle, SECItem *crlKey, int type);
+
+CERTSignedCrl *
+SEC_FindCrlByDERCert(CERTCertDBHandle *handle, SECItem *derCrl, int type);
+
+PRBool
+SEC_CertNicknameConflict(char *nickname, SECItem *derSubject,
+ CERTCertDBHandle *handle);
+CERTSignedCrl *
+SEC_NewCrl(CERTCertDBHandle *handle, char *url, SECItem *derCrl, int type);
+
+SECStatus
+SEC_DeletePermCRL(CERTSignedCrl *crl);
+
+
+SECStatus
+SEC_LookupCrls(CERTCertDBHandle *handle, CERTCrlHeadNode **nodes, int type);
+
+SECStatus
+SEC_DestroyCrl(CERTSignedCrl *crl);
+
+SECStatus
+CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname,
+ CERTCertTrust *trust);
+
+SECStatus SEC_DeletePermCertificate(CERTCertificate *cert);
+
+PRBool
+SEC_CrlIsNewer(CERTCrl *inNew, CERTCrl *old);
+
+SECCertTimeValidity
+SEC_CheckCrlTimes(CERTCrl *crl, PRTime t);
+
+#ifdef notdef
+/*
+** Add a DER encoded certificate to the permanent database.
+** "derCert" is the DER encoded certificate.
+** "nickname" is the nickname to use for the cert
+** "trust" is the trust parameters for the cert
+*/
+SECStatus SEC_AddPermCertificate(PCERTCertDBHandle *handle, SECItem *derCert,
+ char *nickname, PCERTCertTrust *trust);
+
+certDBEntryCert *
+SEC_FindPermCertByKey(PCERTCertDBHandle *handle, SECItem *certKey);
+
+certDBEntryCert
+*SEC_FindPermCertByName(PCERTCertDBHandle *handle, SECItem *name);
+
+SECStatus SEC_OpenPermCertDB(PCERTCertDBHandle *handle,
+ PRBool readOnly,
+ PCERTDBNameFunc namecb,
+ void *cbarg);
+
+
+typedef SECStatus (PR_CALLBACK * PermCertCallback)(PCERTCertificate *cert,
+ SECItem *k, void *pdata);
+/*
+** Traverse the entire permanent database, and pass the certs off to a
+** user supplied function.
+** "certfunc" is the user function to call for each certificate
+** "udata" is the user's data, which is passed through to "certfunc"
+*/
+SECStatus
+PCERT_TraversePermCerts(PCERTCertDBHandle *handle,
+ PermCertCallback certfunc,
+ void *udata );
+
+SECStatus
+SEC_AddTempNickname(PCERTCertDBHandle *handle, char *nickname, SECItem *certKey);
+
+SECStatus
+SEC_DeleteTempNickname(PCERTCertDBHandle *handle, char *nickname);
+
+
+PRBool
+SEC_CertDBKeyConflict(SECItem *derCert, PCERTCertDBHandle *handle);
+
+SECStatus
+SEC_GetCrlTimes(PCERTCrl *dates, PRTime *notBefore, PRTime *notAfter);
+
+PCERTSignedCrl *
+SEC_AddPermCrlToTemp(PCERTCertDBHandle *handle, certDBEntryRevocation *entry);
+
+SECStatus
+SEC_DeleteTempCrl(PCERTSignedCrl *crl);
+
+
+SECStatus
+SEC_CheckKRL(PCERTCertDBHandle *handle,SECKEYLowPublicKey *key,
+ PCERTCertificate *rootCert, int64 t, void *wincx);
+
+SECStatus
+SEC_CheckCRL(PCERTCertDBHandle *handle,PCERTCertificate *cert,
+ PCERTCertificate *caCert, int64 t, void *wincx);
+
+SECStatus
+SEC_CrlReplaceUrl(PCERTSignedCrl *crl,char *url);
+#endif
+
+SEC_END_PROTOS
+
+#endif /* _CERTDB_H_ */
diff --git a/security/nss/lib/certdb/certi.h b/security/nss/lib/certdb/certi.h
new file mode 100644
index 000000000..d22acab3d
--- /dev/null
+++ b/security/nss/lib/certdb/certi.h
@@ -0,0 +1,213 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+/*
+ * certi.h - private data structures for the certificate library
+ *
+ * $Id$
+ */
+#ifndef _CERTI_H_
+#define _CERTI_H_
+
+#include "certt.h"
+#include "nssrwlkt.h"
+
+#define USE_RWLOCK 1
+
+/* all definitions in this file are subject to change */
+
+typedef struct OpaqueCRLFieldsStr OpaqueCRLFields;
+typedef struct CRLEntryCacheStr CRLEntryCache;
+typedef struct CRLDPCacheStr CRLDPCache;
+typedef struct CRLIssuerCacheStr CRLIssuerCache;
+typedef struct CRLCacheStr CRLCache;
+
+struct OpaqueCRLFieldsStr {
+ PRBool partial;
+ PRBool badEntries;
+ PRBool bad;
+ PRBool badDER;
+ PRBool badExtensions;
+ PRBool deleted;
+ PRBool heapDER;
+ PRBool unverified;
+};
+
+typedef struct PreAllocatorStr PreAllocator;
+
+struct PreAllocatorStr
+{
+ PRSize len;
+ void* data;
+ PRSize used;
+ PRArenaPool* arena;
+ PRSize extra;
+};
+
+/* CRL entry cache.
+ This is the same as an entry plus the next/prev pointers for the hash table
+*/
+
+struct CRLEntryCacheStr {
+ CERTCrlEntry entry;
+ CRLEntryCache *prev, *next;
+};
+
+#define CRL_CACHE_INVALID_CRLS 0x0001 /* this state will be set
+ if we have CRL objects with an invalid DER or signature. Can be
+ cleared if the invalid objects are deleted from the token */
+#define CRL_CACHE_LAST_FETCH_FAILED 0x0002 /* this state will be set
+ if the last CRL fetch encountered an error. Can be cleared if a
+ new fetch succeeds */
+
+#define CRL_CACHE_OUT_OF_MEMORY 0x0004 /* this state will be set
+ if we don't have enough memory to build the hash table of entries */
+
+/* CRL distribution point cache object
+ This is a cache of CRL entries for a given distribution point of an issuer
+ It is built from a collection of one full and 0 or more delta CRLs.
+*/
+
+struct CRLDPCacheStr {
+#ifdef USE_RWLOCK
+ NSSRWLock* lock;
+#else
+ PRLock* lock;
+#endif
+ CERTCertificate* issuer; /* cert issuer */
+ SECItem* subject; /* DER of issuer subject */
+ SECItem* distributionPoint; /* DER of distribution point. This may be
+ NULL when distribution points aren't
+ in use (ie. the CA has a single CRL) */
+
+ /* hash table of entries. We use a PLHashTable and pre-allocate the
+ required amount of memory in one shot, so that our allocator can
+ simply pass offsets into it when hashing.
+
+ This won't work anymore when we support delta CRLs and iCRLs, because
+ the size of the hash table will vary over time. At that point, the best
+ solution will be to allocate large CRLEntry structures by modifying
+ the DER decoding template. The extra space would be for next/prev
+ pointers. This would allow entries from different CRLs to be mixed in
+ the same hash table.
+ */
+ PLHashTable* entries;
+ PreAllocator* prebuffer; /* big pre-allocated buffer mentioned above */
+
+ /* array of CRLs matching this distribution point */
+ PRUint32 ncrls; /* total number of CRLs in crls */
+ CERTSignedCrl** crls; /* array of all matching DER CRLs
+ from all tokens */
+ /* XCRL With iCRLs and multiple DPs, the CRL can be shared accross several
+ issuers. In the future, we'll need to globally recycle the CRL in a
+ separate list in order to avoid extra lookups, decodes, and copies */
+
+ /* pointers to good decoded CRLs used to build the cache */
+ CERTSignedCrl* full; /* full CRL used for the cache */
+#if 0
+ /* for future use */
+ PRInt32 numdeltas; /* number of delta CRLs used for the cache */
+ CERTSignedCrl** deltas; /* delta CRLs used for the cache */
+#endif
+ /* invalidity bitflag */
+ PRUint16 invalid; /* this state will be set if either
+ CRL_CACHE_INVALID_CRLS or CRL_CACHE_LAST_FETCH_FAILED is set.
+ In those cases, all certs are considered revoked as a
+ security precaution. The invalid state can only be cleared
+ during an update if all error states are cleared */
+};
+
+/* CRL issuer cache object
+ This object tracks all the distribution point caches for a given issuer.
+ XCRL once we support multiple issuing distribution points, this object
+ will be a hash table. For now, it just holds the single CRL distribution
+ point cache structure.
+*/
+
+struct CRLIssuerCacheStr {
+ SECItem* subject; /* DER of issuer subject */
+ CRLDPCache dp; /* DER of distribution point */
+ CRLDPCache* dpp;
+#if 0
+ /* XCRL for future use.
+ We don't need to lock at the moment because we only have one DP,
+ which gets created at the same time as this object */
+ NSSRWLock* lock;
+ CRLDPCache** dps;
+ PLHashTable* distributionpoints;
+ CERTCertificate* issuer;
+#endif
+};
+
+/* CRL revocation cache object
+ This object tracks all the issuer caches
+*/
+
+struct CRLCacheStr {
+ PRLock* lock;
+ /* hash table of issuer to CRLIssuerCacheStr,
+ indexed by issuer DER subject */
+ PLHashTable* issuers;
+};
+
+SECStatus InitCRLCache(void);
+SECStatus ShutdownCRLCache(void);
+
+/* 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.
+*/
+extern char * cert_GetCertificateEmailAddresses(CERTCertificate *cert);
+
+/*
+ * These functions are used to map subjectKeyID extension values to certs.
+ */
+SECStatus
+cert_CreateSubjectKeyIDHashTable(void);
+
+SECStatus
+cert_AddSubjectKeyIDMapping(SECItem *subjKeyID, CERTCertificate *cert);
+
+/*
+ * Call this function to remove an entry from the mapping table.
+ */
+SECStatus
+cert_RemoveSubjectKeyIDMapping(SECItem *subjKeyID);
+
+SECStatus
+cert_DestroySubjectKeyIDHashTable(void);
+
+SECItem*
+cert_FindDERCertBySubjectKeyID(SECItem *subjKeyID);
+
+#endif /* _CERTI_H_ */
+
diff --git a/security/nss/lib/certdb/certt.h b/security/nss/lib/certdb/certt.h
new file mode 100644
index 000000000..f6b8f74bc
--- /dev/null
+++ b/security/nss/lib/certdb/certt.h
@@ -0,0 +1,853 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+/*
+ * certt.h - public data structures for the certificate library
+ *
+ * $Id$
+ */
+#ifndef _CERTT_H_
+#define _CERTT_H_
+
+#include "prclist.h"
+#include "pkcs11t.h"
+#include "seccomon.h"
+#include "secmodt.h"
+#include "secoidt.h"
+#include "plarena.h"
+#include "prcvar.h"
+#include "nssilock.h"
+#include "prio.h"
+#include "prmon.h"
+
+/* Stan data types */
+struct NSSCertificateStr;
+struct NSSTrustDomainStr;
+
+/* Non-opaque objects */
+typedef struct CERTAVAStr CERTAVA;
+typedef struct CERTAttributeStr CERTAttribute;
+typedef struct CERTAuthInfoAccessStr CERTAuthInfoAccess;
+typedef struct CERTAuthKeyIDStr CERTAuthKeyID;
+typedef struct CERTBasicConstraintsStr CERTBasicConstraints;
+#ifdef NSS_CLASSIC
+typedef struct CERTCertDBHandleStr CERTCertDBHandle;
+#else
+typedef struct NSSTrustDomainStr CERTCertDBHandle;
+#endif
+typedef struct CERTCertExtensionStr CERTCertExtension;
+typedef struct CERTCertKeyStr CERTCertKey;
+typedef struct CERTCertListStr CERTCertList;
+typedef struct CERTCertListNodeStr CERTCertListNode;
+typedef struct CERTCertNicknamesStr CERTCertNicknames;
+typedef struct CERTCertTrustStr CERTCertTrust;
+typedef struct CERTCertificateStr CERTCertificate;
+typedef struct CERTCertificateListStr CERTCertificateList;
+typedef struct CERTCertificateRequestStr CERTCertificateRequest;
+typedef struct CERTCrlStr CERTCrl;
+typedef struct CERTCrlDistributionPointsStr CERTCrlDistributionPoints;
+typedef struct CERTCrlEntryStr CERTCrlEntry;
+typedef struct CERTCrlHeadNodeStr CERTCrlHeadNode;
+typedef struct CERTCrlKeyStr CERTCrlKey;
+typedef struct CERTCrlNodeStr CERTCrlNode;
+typedef struct CERTDERCertsStr CERTDERCerts;
+typedef struct CERTDistNamesStr CERTDistNames;
+typedef struct CERTGeneralNameStr CERTGeneralName;
+typedef struct CERTGeneralNameListStr CERTGeneralNameList;
+typedef struct CERTIssuerAndSNStr CERTIssuerAndSN;
+typedef struct CERTNameStr CERTName;
+typedef struct CERTNameConstraintStr CERTNameConstraint;
+typedef struct CERTNameConstraintsStr CERTNameConstraints;
+typedef struct CERTOKDomainNameStr CERTOKDomainName;
+typedef struct CERTPublicKeyAndChallengeStr CERTPublicKeyAndChallenge;
+typedef struct CERTRDNStr CERTRDN;
+typedef struct CERTSignedCrlStr CERTSignedCrl;
+typedef struct CERTSignedDataStr CERTSignedData;
+typedef struct CERTStatusConfigStr CERTStatusConfig;
+typedef struct CERTSubjectListStr CERTSubjectList;
+typedef struct CERTSubjectNodeStr CERTSubjectNode;
+typedef struct CERTSubjectPublicKeyInfoStr CERTSubjectPublicKeyInfo;
+typedef struct CERTValidityStr CERTValidity;
+typedef struct CERTVerifyLogStr CERTVerifyLog;
+typedef struct CERTVerifyLogNodeStr CERTVerifyLogNode;
+typedef struct CRLDistributionPointStr CRLDistributionPoint;
+
+/* CRL extensions type */
+typedef unsigned long CERTCrlNumber;
+
+/*
+** An X.500 AVA object
+*/
+struct CERTAVAStr {
+ SECItem type;
+ SECItem value;
+};
+
+/*
+** An X.500 RDN object
+*/
+struct CERTRDNStr {
+ CERTAVA **avas;
+};
+
+/*
+** An X.500 name object
+*/
+struct CERTNameStr {
+ PRArenaPool *arena;
+ CERTRDN **rdns;
+};
+
+/*
+** An X.509 validity object
+*/
+struct CERTValidityStr {
+ PRArenaPool *arena;
+ SECItem notBefore;
+ SECItem notAfter;
+};
+
+/*
+ * A serial number and issuer name, which is used as a database key
+ */
+struct CERTCertKeyStr {
+ SECItem serialNumber;
+ SECItem derIssuer;
+};
+
+/*
+** A signed data object. Used to implement the "signed" macro used
+** in the X.500 specs.
+*/
+struct CERTSignedDataStr {
+ SECItem data;
+ SECAlgorithmID signatureAlgorithm;
+ SECItem signature;
+};
+
+/*
+** An X.509 subject-public-key-info object
+*/
+struct CERTSubjectPublicKeyInfoStr {
+ PRArenaPool *arena;
+ SECAlgorithmID algorithm;
+ SECItem subjectPublicKey;
+};
+
+struct CERTPublicKeyAndChallengeStr {
+ SECItem spki;
+ SECItem challenge;
+};
+
+struct CERTCertTrustStr {
+ unsigned int sslFlags;
+ unsigned int emailFlags;
+ unsigned int objectSigningFlags;
+};
+
+/*
+ * defined the types of trust that exist
+ */
+typedef enum SECTrustTypeEnum {
+ trustSSL = 0,
+ trustEmail = 1,
+ trustObjectSigning = 2,
+ trustTypeNone = 3
+} SECTrustType;
+
+#define SEC_GET_TRUST_FLAGS(trust,type) \
+ (((type)==trustSSL)?((trust)->sslFlags): \
+ (((type)==trustEmail)?((trust)->emailFlags): \
+ (((type)==trustObjectSigning)?((trust)->objectSigningFlags):0)))
+
+/*
+** An X.509.3 certificate extension
+*/
+struct CERTCertExtensionStr {
+ SECItem id;
+ SECItem critical;
+ SECItem value;
+};
+
+struct CERTSubjectNodeStr {
+ struct CERTSubjectNodeStr *next;
+ struct CERTSubjectNodeStr *prev;
+ SECItem certKey;
+ SECItem keyID;
+};
+
+struct CERTSubjectListStr {
+ PRArenaPool *arena;
+ int ncerts;
+ char *emailAddr;
+ CERTSubjectNode *head;
+ CERTSubjectNode *tail; /* do we need tail? */
+ void *entry;
+};
+
+/*
+** An X.509 certificate object (the unsigned form)
+*/
+struct CERTCertificateStr {
+ /* the arena is used to allocate any data structures that have the same
+ * lifetime as the cert. This is all stuff that hangs off of the cert
+ * structure, and is all freed at the same time. I is used when the
+ * cert is decoded, destroyed, and at some times when it changes
+ * state
+ */
+ PRArenaPool *arena;
+
+ /* The following fields are static after the cert has been decoded */
+ char *subjectName;
+ char *issuerName;
+ CERTSignedData signatureWrap; /* XXX */
+ SECItem derCert; /* original DER for the cert */
+ SECItem derIssuer; /* DER for issuer name */
+ SECItem derSubject; /* DER for subject name */
+ SECItem derPublicKey; /* DER for the public key */
+ SECItem certKey; /* database key for this cert */
+ SECItem version;
+ SECItem serialNumber;
+ SECAlgorithmID signature;
+ CERTName issuer;
+ CERTValidity validity;
+ CERTName subject;
+ CERTSubjectPublicKeyInfo subjectPublicKeyInfo;
+ SECItem issuerID;
+ SECItem subjectID;
+ CERTCertExtension **extensions;
+ char *emailAddr;
+ CERTCertDBHandle *dbhandle;
+ SECItem subjectKeyID; /* x509v3 subject key identifier */
+ PRBool keyIDGenerated; /* was the keyid generated? */
+ unsigned int keyUsage; /* what uses are allowed for this cert */
+ unsigned int rawKeyUsage; /* value of the key usage extension */
+ PRBool keyUsagePresent; /* was the key usage extension present */
+ unsigned int nsCertType; /* value of the ns cert type extension */
+
+ /* these values can be set by the application to bypass certain checks
+ * or to keep the cert in memory for an entire session.
+ * XXX - need an api to set these
+ */
+ PRBool keepSession; /* keep this cert for entire session*/
+ PRBool timeOK; /* is the bad validity time ok? */
+ CERTOKDomainName *domainOK; /* these domain names are ok */
+
+ /*
+ * these values can change when the cert changes state. These state
+ * changes include transitions from temp to perm or vice-versa, and
+ * changes of trust flags
+ */
+ PRBool isperm;
+ PRBool istemp;
+ char *nickname;
+ char *dbnickname;
+ struct NSSCertificateStr *nssCertificate; /* This is Stan stuff. */
+ CERTCertTrust *trust;
+
+ /* the reference count is modified whenever someone looks up, dups
+ * or destroys a certificate
+ */
+ int referenceCount;
+
+ /* The subject list is a list of all certs with the same subject name.
+ * It can be modified any time a cert is added or deleted from either
+ * the in-memory(temporary) or on-disk(permanent) database.
+ */
+ CERTSubjectList *subjectList;
+
+ /* these belong in the static section, but are here to maintain
+ * the structure's integrity
+ */
+ CERTAuthKeyID * authKeyID; /* x509v3 authority key identifier */
+ PRBool isRoot; /* cert is the end of a chain */
+
+ /* these fields are used by client GUI code to keep track of ssl sockets
+ * that are blocked waiting on GUI feedback related to this cert.
+ * XXX - these should be moved into some sort of application specific
+ * data structure. They are only used by the browser right now.
+ */
+ struct SECSocketNode *authsocketlist;
+ int series; /* was int authsocketcount; record the series of the pkcs11ID */
+
+ /* This is PKCS #11 stuff. */
+ PK11SlotInfo *slot; /*if this cert came of a token, which is it*/
+ CK_OBJECT_HANDLE pkcs11ID; /*and which object on that token is it */
+ PRBool ownSlot; /*true if the cert owns the slot reference */
+};
+#define SEC_CERTIFICATE_VERSION_1 0 /* default created */
+#define SEC_CERTIFICATE_VERSION_2 1 /* v2 */
+#define SEC_CERTIFICATE_VERSION_3 2 /* v3 extensions */
+
+#define SEC_CRL_VERSION_1 0 /* default */
+#define SEC_CRL_VERSION_2 1 /* v2 extensions */
+
+/*
+ * used to identify class of cert in mime stream code
+ */
+#define SEC_CERT_CLASS_CA 1
+#define SEC_CERT_CLASS_SERVER 2
+#define SEC_CERT_CLASS_USER 3
+#define SEC_CERT_CLASS_EMAIL 4
+
+struct CERTDERCertsStr {
+ PRArenaPool *arena;
+ int numcerts;
+ SECItem *rawCerts;
+};
+
+/*
+** A PKCS ? Attribute
+** XXX this is duplicated through out the code, it *should* be moved
+** to a central location. Where would be appropriate?
+*/
+struct CERTAttributeStr {
+ SECItem attrType;
+ SECItem **attrValue;
+};
+
+/*
+** A PKCS#10 certificate-request object (the unsigned form)
+*/
+struct CERTCertificateRequestStr {
+ PRArenaPool *arena;
+ SECItem version;
+ CERTName subject;
+ CERTSubjectPublicKeyInfo subjectPublicKeyInfo;
+ SECItem **attributes;
+};
+#define SEC_CERTIFICATE_REQUEST_VERSION 0 /* what we *create* */
+
+
+/*
+** A certificate list object.
+*/
+struct CERTCertificateListStr {
+ SECItem *certs;
+ int len; /* number of certs */
+ PRArenaPool *arena;
+};
+
+struct CERTCertListNodeStr {
+ PRCList links;
+ CERTCertificate *cert;
+ void *appData;
+};
+
+struct CERTCertListStr {
+ PRCList list;
+ PRArenaPool *arena;
+};
+
+#define CERT_LIST_HEAD(l) ((CERTCertListNode *)PR_LIST_HEAD(&l->list))
+#define CERT_LIST_NEXT(n) ((CERTCertListNode *)n->links.next)
+#define CERT_LIST_END(n,l) (((void *)n) == ((void *)&l->list))
+#define CERT_LIST_EMPTY(l) CERT_LIST_END(CERT_LIST_HEAD(l), l)
+
+struct CERTCrlEntryStr {
+ SECItem serialNumber;
+ SECItem revocationDate;
+ CERTCertExtension **extensions;
+};
+
+struct CERTCrlStr {
+ PRArenaPool *arena;
+ SECItem version;
+ SECAlgorithmID signatureAlg;
+ SECItem derName;
+ CERTName name;
+ SECItem lastUpdate;
+ SECItem nextUpdate; /* optional for x.509 CRL */
+ CERTCrlEntry **entries;
+ CERTCertExtension **extensions;
+ /* can't add anything there for binary backwards compatibility reasons */
+};
+
+struct CERTCrlKeyStr {
+ SECItem derName;
+ SECItem dummy; /* The decoder can not skip a primitive,
+ this serves as a place holder for the
+ decoder to finish its task only
+ */
+};
+
+struct CERTSignedCrlStr {
+ PRArenaPool *arena;
+ CERTCrl crl;
+ void *reserved1;
+ PRBool reserved2;
+ PRBool isperm;
+ PRBool istemp;
+ int referenceCount;
+ CERTCertDBHandle *dbhandle;
+ CERTSignedData signatureWrap; /* XXX */
+ char *url;
+ SECItem *derCrl;
+ PK11SlotInfo *slot;
+ CK_OBJECT_HANDLE pkcs11ID;
+ void* opaque; /* do not touch */
+};
+
+
+struct CERTCrlHeadNodeStr {
+ PRArenaPool *arena;
+ CERTCertDBHandle *dbhandle;
+ CERTCrlNode *first;
+ CERTCrlNode *last;
+};
+
+
+struct CERTCrlNodeStr {
+ CERTCrlNode *next;
+ int type;
+ CERTSignedCrl *crl;
+};
+
+
+/*
+ * Array of X.500 Distinguished Names
+ */
+struct CERTDistNamesStr {
+ PRArenaPool *arena;
+ int nnames;
+ SECItem *names;
+ void *head; /* private */
+};
+
+
+#define NS_CERT_TYPE_SSL_CLIENT (0x80) /* bit 0 */
+#define NS_CERT_TYPE_SSL_SERVER (0x40) /* bit 1 */
+#define NS_CERT_TYPE_EMAIL (0x20) /* bit 2 */
+#define NS_CERT_TYPE_OBJECT_SIGNING (0x10) /* bit 3 */
+#define NS_CERT_TYPE_RESERVED (0x08) /* bit 4 */
+#define NS_CERT_TYPE_SSL_CA (0x04) /* bit 5 */
+#define NS_CERT_TYPE_EMAIL_CA (0x02) /* bit 6 */
+#define NS_CERT_TYPE_OBJECT_SIGNING_CA (0x01) /* bit 7 */
+
+#define EXT_KEY_USAGE_TIME_STAMP (0x8000)
+#define EXT_KEY_USAGE_STATUS_RESPONDER (0x4000)
+
+#define NS_CERT_TYPE_APP ( NS_CERT_TYPE_SSL_CLIENT | \
+ NS_CERT_TYPE_SSL_SERVER | \
+ NS_CERT_TYPE_EMAIL | \
+ NS_CERT_TYPE_OBJECT_SIGNING )
+
+#define NS_CERT_TYPE_CA ( NS_CERT_TYPE_SSL_CA | \
+ NS_CERT_TYPE_EMAIL_CA | \
+ NS_CERT_TYPE_OBJECT_SIGNING_CA | \
+ EXT_KEY_USAGE_STATUS_RESPONDER )
+typedef enum SECCertUsageEnum {
+ certUsageSSLClient = 0,
+ certUsageSSLServer = 1,
+ certUsageSSLServerWithStepUp = 2,
+ certUsageSSLCA = 3,
+ certUsageEmailSigner = 4,
+ certUsageEmailRecipient = 5,
+ certUsageObjectSigner = 6,
+ certUsageUserCertImport = 7,
+ certUsageVerifyCA = 8,
+ certUsageProtectedObjectSigner = 9,
+ certUsageStatusResponder = 10,
+ certUsageAnyCA = 11
+} SECCertUsage;
+
+typedef PRInt64 SECCertificateUsage;
+
+#define certificateUsageSSLClient (0x0001)
+#define certificateUsageSSLServer (0x0002)
+#define certificateUsageSSLServerWithStepUp (0x0004)
+#define certificateUsageSSLCA (0x0008)
+#define certificateUsageEmailSigner (0x0010)
+#define certificateUsageEmailRecipient (0x0020)
+#define certificateUsageObjectSigner (0x0040)
+#define certificateUsageUserCertImport (0x0080)
+#define certificateUsageVerifyCA (0x0100)
+#define certificateUsageProtectedObjectSigner (0x0200)
+#define certificateUsageStatusResponder (0x0400)
+#define certificateUsageAnyCA (0x0800)
+
+#define certificateUsageHighest certificateUsageAnyCA
+
+/*
+ * Does the cert belong to the user, a peer, or a CA.
+ */
+typedef enum CERTCertOwnerEnum {
+ certOwnerUser = 0,
+ certOwnerPeer = 1,
+ certOwnerCA = 2
+} CERTCertOwner;
+
+/*
+ * This enum represents the state of validity times of a certificate
+ */
+typedef enum SECCertTimeValidityEnum {
+ secCertTimeValid = 0,
+ secCertTimeExpired = 1,
+ secCertTimeNotValidYet = 2
+} SECCertTimeValidity;
+
+/*
+ * Interface for getting certificate nickname strings out of the database
+ */
+
+/* these are values for the what argument below */
+#define SEC_CERT_NICKNAMES_ALL 1
+#define SEC_CERT_NICKNAMES_USER 2
+#define SEC_CERT_NICKNAMES_SERVER 3
+#define SEC_CERT_NICKNAMES_CA 4
+
+struct CERTCertNicknamesStr {
+ PRArenaPool *arena;
+ void *head;
+ int numnicknames;
+ char **nicknames;
+ int what;
+ int totallen;
+};
+
+struct CERTIssuerAndSNStr {
+ SECItem derIssuer;
+ CERTName issuer;
+ SECItem serialNumber;
+};
+
+
+/* X.509 v3 Key Usage Extension flags */
+#define KU_DIGITAL_SIGNATURE (0x80) /* bit 0 */
+#define KU_NON_REPUDIATION (0x40) /* bit 1 */
+#define KU_KEY_ENCIPHERMENT (0x20) /* bit 2 */
+#define KU_DATA_ENCIPHERMENT (0x10) /* bit 3 */
+#define KU_KEY_AGREEMENT (0x08) /* bit 4 */
+#define KU_KEY_CERT_SIGN (0x04) /* bit 5 */
+#define KU_CRL_SIGN (0x02) /* bit 6 */
+#define KU_ALL (KU_DIGITAL_SIGNATURE | \
+ KU_NON_REPUDIATION | \
+ KU_KEY_ENCIPHERMENT | \
+ KU_DATA_ENCIPHERMENT | \
+ KU_KEY_AGREEMENT | \
+ KU_KEY_CERT_SIGN | \
+ KU_CRL_SIGN)
+
+/* This value will not occur in certs. It is used internally for the case
+ * when the key type is not know ahead of time and either key agreement or
+ * key encipherment are the correct value based on key type
+ */
+#define KU_KEY_AGREEMENT_OR_ENCIPHERMENT (0x4000)
+
+/* internal bits that do not match bits in the x509v3 spec, but are used
+ * for similar purposes
+ */
+#define KU_NS_GOVT_APPROVED (0x8000) /*don't make part of KU_ALL!*/
+/*
+ * x.509 v3 Basic Constraints Extension
+ * If isCA is false, the pathLenConstraint is ignored.
+ * Otherwise, the following pathLenConstraint values will apply:
+ * < 0 - there is no limit to the certificate path
+ * 0 - CA can issues end-entity certificates only
+ * > 0 - the number of certificates in the certificate path is
+ * limited to this number
+ */
+#define CERT_UNLIMITED_PATH_CONSTRAINT -2
+
+struct CERTBasicConstraintsStr {
+ PRBool isCA; /* on if is CA */
+ int pathLenConstraint; /* maximum number of certificates that can be
+ in the cert path. Only applies to a CA
+ certificate; otherwise, it's ignored.
+ */
+};
+
+/* Maximum length of a certificate chain */
+#define CERT_MAX_CERT_CHAIN 20
+
+/* x.509 v3 Reason Falgs, used in CRLDistributionPoint Extension */
+#define RF_UNUSED (0x80) /* bit 0 */
+#define RF_KEY_COMPROMISE (0x40) /* bit 1 */
+#define RF_CA_COMPROMISE (0x20) /* bit 2 */
+#define RF_AFFILIATION_CHANGED (0x10) /* bit 3 */
+#define RF_SUPERSEDED (0x08) /* bit 4 */
+#define RF_CESSATION_OF_OPERATION (0x04) /* bit 5 */
+#define RF_CERTIFICATE_HOLD (0x02) /* bit 6 */
+
+/* If we needed to extract the general name field, use this */
+/* General Name types */
+typedef enum CERTGeneralNameTypeEnum {
+ certOtherName = 1,
+ certRFC822Name = 2,
+ certDNSName = 3,
+ certX400Address = 4,
+ certDirectoryName = 5,
+ certEDIPartyName = 6,
+ certURI = 7,
+ certIPAddress = 8,
+ certRegisterID = 9
+} CERTGeneralNameType;
+
+
+typedef struct OtherNameStr {
+ SECItem name;
+ SECItem oid;
+}OtherName;
+
+
+
+struct CERTGeneralNameStr {
+ CERTGeneralNameType type; /* name type */
+ union {
+ CERTName directoryName; /* distinguish name */
+ OtherName OthName; /* Other Name */
+ SECItem other; /* the rest of the name forms */
+ }name;
+ SECItem derDirectoryName; /* this is saved to simplify directory name
+ comparison */
+ PRCList l;
+};
+
+struct CERTGeneralNameListStr {
+ PRArenaPool *arena;
+ CERTGeneralName *name;
+ int refCount;
+ int len;
+ PZLock *lock;
+};
+
+struct CERTNameConstraintStr {
+ CERTGeneralName name;
+ SECItem DERName;
+ SECItem min;
+ SECItem max;
+ PRCList l;
+};
+
+
+struct CERTNameConstraintsStr {
+ CERTNameConstraint *permited;
+ CERTNameConstraint *excluded;
+ SECItem **DERPermited;
+ SECItem **DERExcluded;
+};
+
+
+/* X.509 v3 Authority Key Identifier extension. For the authority certificate
+ issuer field, we only support URI now.
+ */
+struct CERTAuthKeyIDStr {
+ SECItem keyID; /* unique key identifier */
+ CERTGeneralName *authCertIssuer; /* CA's issuer name. End with a NULL */
+ SECItem authCertSerialNumber; /* CA's certificate serial number */
+ SECItem **DERAuthCertIssuer; /* This holds the DER encoded format of
+ the authCertIssuer field. It is used
+ by the encoding engine. It should be
+ used as a read only field by the caller.
+ */
+};
+
+/* x.509 v3 CRL Distributeion Point */
+
+/*
+ * defined the types of CRL Distribution points
+ */
+typedef enum DistributionPointTypesEnum {
+ generalName = 1, /* only support this for now */
+ relativeDistinguishedName = 2
+} DistributionPointTypes;
+
+struct CRLDistributionPointStr {
+ DistributionPointTypes distPointType;
+ union {
+ CERTGeneralName *fullName;
+ CERTRDN relativeName;
+ } distPoint;
+ SECItem reasons;
+ CERTGeneralName *crlIssuer;
+
+ /* Reserved for internal use only*/
+ SECItem derDistPoint;
+ SECItem derRelativeName;
+ SECItem **derCrlIssuer;
+ SECItem **derFullName;
+ SECItem bitsmap;
+};
+
+struct CERTCrlDistributionPointsStr {
+ CRLDistributionPoint **distPoints;
+};
+
+/*
+ * This structure is used to keep a log of errors when verifying
+ * a cert chain. This allows multiple errors to be reported all at
+ * once.
+ */
+struct CERTVerifyLogNodeStr {
+ CERTCertificate *cert; /* what cert had the error */
+ long error; /* what error was it? */
+ unsigned int depth; /* how far up the chain are we */
+ void *arg; /* error specific argument */
+ struct CERTVerifyLogNodeStr *next; /* next in the list */
+ struct CERTVerifyLogNodeStr *prev; /* next in the list */
+};
+
+
+struct CERTVerifyLogStr {
+ PRArenaPool *arena;
+ unsigned int count;
+ struct CERTVerifyLogNodeStr *head;
+ struct CERTVerifyLogNodeStr *tail;
+};
+
+
+struct CERTOKDomainNameStr {
+ CERTOKDomainName *next;
+ char name[1]; /* actual length may be longer. */
+};
+
+
+typedef SECStatus (PR_CALLBACK *CERTStatusChecker) (CERTCertDBHandle *handle,
+ CERTCertificate *cert,
+ int64 time,
+ void *pwArg);
+
+typedef SECStatus (PR_CALLBACK *CERTStatusDestroy) (CERTStatusConfig *handle);
+
+struct CERTStatusConfigStr {
+ CERTStatusChecker statusChecker; /* NULL means no checking enabled */
+ CERTStatusDestroy statusDestroy; /* enabled or no, will clean up */
+ void *statusContext; /* cx specific to checking protocol */
+};
+
+struct CERTAuthInfoAccessStr {
+ SECItem method;
+ SECItem derLocation;
+ CERTGeneralName *location; /* decoded location */
+};
+
+
+/* This is the typedef for the callback passed to CERT_OpenCertDB() */
+/* callback to return database name based on version number */
+typedef char * (*CERTDBNameFunc)(void *arg, int dbVersion);
+
+/*
+ * types of cert packages that we can decode
+ */
+typedef enum CERTPackageTypeEnum {
+ certPackageNone = 0,
+ certPackageCert = 1,
+ certPackagePKCS7 = 2,
+ certPackageNSCertSeq = 3,
+ certPackageNSCertWrap = 4
+} CERTPackageType;
+
+/*
+ * these types are for the PKIX Certificate Policies extension
+ */
+typedef struct {
+ SECOidTag oid;
+ SECItem qualifierID;
+ SECItem qualifierValue;
+} CERTPolicyQualifier;
+
+typedef struct {
+ SECOidTag oid;
+ SECItem policyID;
+ CERTPolicyQualifier **policyQualifiers;
+} CERTPolicyInfo;
+
+typedef struct {
+ PRArenaPool *arena;
+ CERTPolicyInfo **policyInfos;
+} CERTCertificatePolicies;
+
+typedef struct {
+ SECItem organization;
+ SECItem **noticeNumbers;
+} CERTNoticeReference;
+
+typedef struct {
+ PRArenaPool *arena;
+ CERTNoticeReference noticeReference;
+ SECItem derNoticeReference;
+ SECItem displayText;
+} CERTUserNotice;
+
+typedef struct {
+ PRArenaPool *arena;
+ SECItem **oids;
+} CERTOidSequence;
+
+
+/* XXX Lisa thinks the template declarations belong in cert.h, not here? */
+
+#include "secasn1t.h" /* way down here because I expect template stuff to
+ * move out of here anyway */
+
+SEC_BEGIN_PROTOS
+
+extern const SEC_ASN1Template CERT_CertificateRequestTemplate[];
+extern const SEC_ASN1Template CERT_CertificateTemplate[];
+extern const SEC_ASN1Template SEC_SignedCertificateTemplate[];
+extern const SEC_ASN1Template CERT_CertExtensionTemplate[];
+extern const SEC_ASN1Template CERT_SequenceOfCertExtensionTemplate[];
+extern const SEC_ASN1Template SECKEY_PublicKeyTemplate[];
+extern const SEC_ASN1Template CERT_SubjectPublicKeyInfoTemplate[];
+extern const SEC_ASN1Template CERT_ValidityTemplate[];
+extern const SEC_ASN1Template CERT_PublicKeyAndChallengeTemplate[];
+extern const SEC_ASN1Template SEC_CertSequenceTemplate[];
+
+extern const SEC_ASN1Template CERT_IssuerAndSNTemplate[];
+extern const SEC_ASN1Template CERT_NameTemplate[];
+extern const SEC_ASN1Template CERT_SetOfSignedCrlTemplate[];
+extern const SEC_ASN1Template CERT_RDNTemplate[];
+extern const SEC_ASN1Template CERT_SignedDataTemplate[];
+extern const SEC_ASN1Template CERT_CrlTemplate[];
+
+/*
+** XXX should the attribute stuff be centralized for all of ns/security?
+*/
+extern const SEC_ASN1Template CERT_AttributeTemplate[];
+extern const SEC_ASN1Template CERT_SetOfAttributeTemplate[];
+
+/* These functions simply return the address of the above-declared templates.
+** This is necessary for Windows DLLs. Sigh.
+*/
+SEC_ASN1_CHOOSER_DECLARE(CERT_CertificateRequestTemplate)
+SEC_ASN1_CHOOSER_DECLARE(CERT_CertificateTemplate)
+SEC_ASN1_CHOOSER_DECLARE(CERT_CrlTemplate)
+SEC_ASN1_CHOOSER_DECLARE(CERT_IssuerAndSNTemplate)
+SEC_ASN1_CHOOSER_DECLARE(CERT_NameTemplate)
+SEC_ASN1_CHOOSER_DECLARE(CERT_SetOfSignedCrlTemplate)
+SEC_ASN1_CHOOSER_DECLARE(CERT_SignedDataTemplate)
+SEC_ASN1_CHOOSER_DECLARE(CERT_SubjectPublicKeyInfoTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_SignedCertificateTemplate)
+
+SEC_END_PROTOS
+
+#endif /* _CERTT_H_ */
diff --git a/security/nss/lib/certdb/certv3.c b/security/nss/lib/certdb/certv3.c
new file mode 100644
index 000000000..e50c66279
--- /dev/null
+++ b/security/nss/lib/certdb/certv3.c
@@ -0,0 +1,406 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+ * Code for dealing with X509.V3 extensions.
+ *
+ * $Id$
+ */
+
+#include "cert.h"
+#include "secitem.h"
+#include "secoid.h"
+#include "secder.h"
+#include "secasn1.h"
+#include "certxutl.h"
+#include "secerr.h"
+
+SECStatus
+CERT_FindCertExtensionByOID(CERTCertificate *cert, SECItem *oid,
+ SECItem *value)
+{
+ return (cert_FindExtensionByOID (cert->extensions, oid, value));
+}
+
+
+SECStatus
+CERT_FindCertExtension(CERTCertificate *cert, int tag, SECItem *value)
+{
+ return (cert_FindExtension (cert->extensions, tag, value));
+}
+
+static void
+SetExts(void *object, CERTCertExtension **exts)
+{
+ CERTCertificate *cert = (CERTCertificate *)object;
+
+ cert->extensions = exts;
+ DER_SetUInteger (cert->arena, &(cert->version), SEC_CERTIFICATE_VERSION_3);
+}
+
+void *
+CERT_StartCertExtensions(CERTCertificate *cert)
+{
+ return (cert_StartExtensions ((void *)cert, cert->arena, SetExts));
+}
+
+/* find the given extension in the certificate of the Issuer of 'cert' */
+SECStatus
+CERT_FindIssuerCertExtension(CERTCertificate *cert, int tag, SECItem *value)
+{
+ CERTCertificate *issuercert;
+ SECStatus rv;
+
+ issuercert = CERT_FindCertByName(cert->dbhandle, &cert->derIssuer);
+ if ( issuercert ) {
+ rv = cert_FindExtension(issuercert->extensions, tag, value);
+ CERT_DestroyCertificate(issuercert);
+ } else {
+ rv = SECFailure;
+ }
+
+ return(rv);
+}
+
+/* find a URL extension in the cert or its CA
+ * apply the base URL string if it exists
+ */
+char *
+CERT_FindCertURLExtension(CERTCertificate *cert, int tag, int catag)
+{
+ SECStatus rv;
+ SECItem urlitem;
+ SECItem baseitem;
+ SECItem urlstringitem = {siBuffer,0};
+ SECItem basestringitem = {siBuffer,0};
+ PRArenaPool *arena = NULL;
+ PRBool hasbase;
+ char *urlstring;
+ char *str;
+ int len;
+ unsigned int i;
+
+ urlstring = NULL;
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if ( ! arena ) {
+ goto loser;
+ }
+
+ hasbase = PR_FALSE;
+ urlitem.data = NULL;
+ baseitem.data = NULL;
+
+ rv = cert_FindExtension(cert->extensions, tag, &urlitem);
+ if ( rv == SECSuccess ) {
+ rv = cert_FindExtension(cert->extensions, SEC_OID_NS_CERT_EXT_BASE_URL,
+ &baseitem);
+ if ( rv == SECSuccess ) {
+ hasbase = PR_TRUE;
+ }
+
+ } else if ( catag ) {
+ /* if the cert doesn't have the extensions, see if the issuer does */
+ rv = CERT_FindIssuerCertExtension(cert, catag, &urlitem);
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+ rv = CERT_FindIssuerCertExtension(cert, SEC_OID_NS_CERT_EXT_BASE_URL,
+ &baseitem);
+ if ( rv == SECSuccess ) {
+ hasbase = PR_TRUE;
+ }
+ } else {
+ goto loser;
+ }
+
+ rv = SEC_QuickDERDecodeItem(arena, &urlstringitem, SEC_IA5StringTemplate,
+ &urlitem);
+
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+ if ( hasbase ) {
+ rv = SEC_QuickDERDecodeItem(arena, &basestringitem, SEC_IA5StringTemplate,
+ &baseitem);
+
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+ }
+
+ len = urlstringitem.len + ( hasbase ? basestringitem.len : 0 ) + 1;
+
+ str = urlstring = (char *)PORT_Alloc(len);
+ if ( urlstring == NULL ) {
+ goto loser;
+ }
+
+ /* copy the URL base first */
+ if ( hasbase ) {
+
+ /* if the urlstring has a : in it, then we assume it is an absolute
+ * URL, and will not get the base string pre-pended
+ */
+ for ( i = 0; i < urlstringitem.len; i++ ) {
+ if ( urlstringitem.data[i] == ':' ) {
+ goto nobase;
+ }
+ }
+
+ PORT_Memcpy(str, basestringitem.data, basestringitem.len);
+ str += basestringitem.len;
+
+ }
+
+nobase:
+ /* copy the rest (or all) of the URL */
+ PORT_Memcpy(str, urlstringitem.data, urlstringitem.len);
+ str += urlstringitem.len;
+
+ *str = '\0';
+ goto done;
+
+loser:
+ if ( urlstring ) {
+ PORT_Free(urlstring);
+ }
+
+ urlstring = NULL;
+done:
+ if ( arena ) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+ if ( baseitem.data ) {
+ PORT_Free(baseitem.data);
+ }
+ if ( urlitem.data ) {
+ PORT_Free(urlitem.data);
+ }
+
+ return(urlstring);
+}
+
+/*
+ * get the value of the Netscape Certificate Type Extension
+ */
+SECStatus
+CERT_FindNSCertTypeExtension(CERTCertificate *cert, SECItem *retItem)
+{
+
+ return (CERT_FindBitStringExtension
+ (cert->extensions, SEC_OID_NS_CERT_EXT_CERT_TYPE, retItem));
+}
+
+
+/*
+ * get the value of a string type extension
+ */
+char *
+CERT_FindNSStringExtension(CERTCertificate *cert, int oidtag)
+{
+ SECItem wrapperItem, tmpItem = {siBuffer,0};
+ SECStatus rv;
+ PRArenaPool *arena = NULL;
+ char *retstring = NULL;
+
+ wrapperItem.data = NULL;
+ tmpItem.data = NULL;
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+
+ if ( ! arena ) {
+ goto loser;
+ }
+
+ rv = cert_FindExtension(cert->extensions, oidtag,
+ &wrapperItem);
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ rv = SEC_QuickDERDecodeItem(arena, &tmpItem, SEC_IA5StringTemplate,
+ &wrapperItem);
+
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ retstring = (char *)PORT_Alloc(tmpItem.len + 1 );
+ if ( retstring == NULL ) {
+ goto loser;
+ }
+
+ PORT_Memcpy(retstring, tmpItem.data, tmpItem.len);
+ retstring[tmpItem.len] = '\0';
+
+loser:
+ if ( arena ) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ if ( wrapperItem.data ) {
+ PORT_Free(wrapperItem.data);
+ }
+
+ return(retstring);
+}
+
+/*
+ * get the value of the X.509 v3 Key Usage Extension
+ */
+SECStatus
+CERT_FindKeyUsageExtension(CERTCertificate *cert, SECItem *retItem)
+{
+
+ return (CERT_FindBitStringExtension(cert->extensions,
+ SEC_OID_X509_KEY_USAGE, retItem));
+}
+
+/*
+ * get the value of the X.509 v3 Key Usage Extension
+ */
+SECStatus
+CERT_FindSubjectKeyIDExtension(CERTCertificate *cert, SECItem *retItem)
+{
+
+ SECItem encodedValue;
+ SECStatus rv;
+
+ encodedValue.data = NULL;
+ rv = cert_FindExtension
+ (cert->extensions, SEC_OID_X509_SUBJECT_KEY_ID, &encodedValue);
+ if (rv != SECSuccess)
+ return (rv);
+ rv = SEC_ASN1DecodeItem (NULL, retItem, SEC_OctetStringTemplate,
+ &encodedValue);
+ PORT_Free (encodedValue.data);
+
+ return (rv);
+}
+
+SECStatus
+CERT_FindBasicConstraintExten(CERTCertificate *cert,
+ CERTBasicConstraints *value)
+{
+ SECItem encodedExtenValue;
+ SECStatus rv;
+
+ encodedExtenValue.data = NULL;
+ encodedExtenValue.len = 0;
+
+ rv = cert_FindExtension(cert->extensions, SEC_OID_X509_BASIC_CONSTRAINTS,
+ &encodedExtenValue);
+ if ( rv != SECSuccess ) {
+ return (rv);
+ }
+
+ rv = CERT_DecodeBasicConstraintValue (value, &encodedExtenValue);
+
+ /* free the raw extension data */
+ PORT_Free(encodedExtenValue.data);
+ encodedExtenValue.data = NULL;
+
+ return(rv);
+}
+
+CERTAuthKeyID *
+CERT_FindAuthKeyIDExten (PRArenaPool *arena, CERTCertificate *cert)
+{
+ SECItem encodedExtenValue;
+ SECStatus rv;
+ CERTAuthKeyID *ret;
+
+ encodedExtenValue.data = NULL;
+ encodedExtenValue.len = 0;
+
+ rv = cert_FindExtension(cert->extensions, SEC_OID_X509_AUTH_KEY_ID,
+ &encodedExtenValue);
+ if ( rv != SECSuccess ) {
+ return (NULL);
+ }
+
+ ret = CERT_DecodeAuthKeyID (arena, &encodedExtenValue);
+
+ PORT_Free(encodedExtenValue.data);
+ encodedExtenValue.data = NULL;
+
+ return(ret);
+}
+
+SECStatus
+CERT_CheckCertUsage(CERTCertificate *cert, unsigned char usage)
+{
+ PRBool critical;
+ SECItem keyUsage;
+ SECStatus rv;
+
+ /* There is no extension, v1 or v2 certificate */
+ if (cert->extensions == NULL) {
+ return (SECSuccess);
+ }
+
+ keyUsage.data = NULL;
+
+ do {
+ /* if the keyUsage extension exists and is critical, make sure that the
+ CA certificate is used for certificate signing purpose only. If the
+ extension does not exist, we will assum that it can be used for
+ certificate signing purpose.
+ */
+ rv = CERT_GetExtenCriticality(cert->extensions,
+ SEC_OID_X509_KEY_USAGE,
+ &critical);
+ if (rv == SECFailure) {
+ rv = (PORT_GetError () == SEC_ERROR_EXTENSION_NOT_FOUND) ?
+ SECSuccess : SECFailure;
+ break;
+ }
+
+ if (critical == PR_FALSE) {
+ rv = SECSuccess;
+ break;
+ }
+
+ rv = CERT_FindKeyUsageExtension(cert, &keyUsage);
+ if (rv != SECSuccess) {
+ break;
+ }
+ if (!(keyUsage.data[0] & usage)) {
+ PORT_SetError (SEC_ERROR_CERT_USAGES_INVALID);
+ rv = SECFailure;
+ }
+ }while (0);
+ PORT_Free (keyUsage.data);
+ return (rv);
+}
diff --git a/security/nss/lib/certdb/certxutl.c b/security/nss/lib/certdb/certxutl.c
new file mode 100644
index 000000000..9e9fa9b97
--- /dev/null
+++ b/security/nss/lib/certdb/certxutl.c
@@ -0,0 +1,482 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+ * Certificate Extensions handling code
+ *
+ */
+
+#include "cert.h"
+#include "secitem.h"
+#include "secoid.h"
+#include "secder.h"
+#include "secasn1.h"
+#include "certxutl.h"
+#include "secerr.h"
+
+#ifdef OLD
+#include "ocspti.h" /* XXX a better extensions interface would not
+ * require knowledge of data structures of callers */
+#endif
+
+static CERTCertExtension *
+GetExtension (CERTCertExtension **extensions, SECItem *oid)
+{
+ CERTCertExtension **exts;
+ CERTCertExtension *ext = NULL;
+ SECComparison comp;
+
+ exts = extensions;
+
+ if (exts) {
+ while ( *exts ) {
+ ext = *exts;
+ comp = SECITEM_CompareItem(oid, &ext->id);
+ if ( comp == SECEqual )
+ break;
+
+ exts++;
+ }
+ return (*exts ? ext : NULL);
+ }
+ return (NULL);
+}
+
+SECStatus
+cert_FindExtensionByOID (CERTCertExtension **extensions, SECItem *oid, SECItem *value)
+{
+ CERTCertExtension *ext;
+ SECStatus rv = SECSuccess;
+
+ ext = GetExtension (extensions, oid);
+ if (ext == NULL) {
+ PORT_SetError (SEC_ERROR_EXTENSION_NOT_FOUND);
+ return (SECFailure);
+ }
+ if (value)
+ rv = SECITEM_CopyItem(NULL, value, &ext->value);
+ return (rv);
+}
+
+
+SECStatus
+CERT_GetExtenCriticality (CERTCertExtension **extensions, int tag, PRBool *isCritical)
+{
+ CERTCertExtension *ext;
+ SECOidData *oid;
+
+ if (!isCritical)
+ return (SECSuccess);
+
+ /* find the extension in the extensions list */
+ oid = SECOID_FindOIDByTag((SECOidTag)tag);
+ if ( !oid ) {
+ return(SECFailure);
+ }
+ ext = GetExtension (extensions, &oid->oid);
+ if (ext == NULL) {
+ PORT_SetError (SEC_ERROR_EXTENSION_NOT_FOUND);
+ return (SECFailure);
+ }
+
+ /* If the criticality is omitted, then it is false by default.
+ ex->critical.data is NULL */
+ if (ext->critical.data == NULL)
+ *isCritical = PR_FALSE;
+ else
+ *isCritical = (ext->critical.data[0] == 0xff) ? PR_TRUE : PR_FALSE;
+ return (SECSuccess);
+}
+
+SECStatus
+cert_FindExtension(CERTCertExtension **extensions, int tag, SECItem *value)
+{
+ SECOidData *oid;
+
+ oid = SECOID_FindOIDByTag((SECOidTag)tag);
+ if ( !oid ) {
+ return(SECFailure);
+ }
+
+ return(cert_FindExtensionByOID(extensions, &oid->oid, value));
+}
+
+
+typedef struct _extNode {
+ struct _extNode *next;
+ CERTCertExtension *ext;
+} extNode;
+
+typedef struct {
+ void (*setExts)(void *object, CERTCertExtension **exts);
+ void *object;
+ PRArenaPool *ownerArena;
+ PRArenaPool *arena;
+ extNode *head;
+ int count;
+}extRec;
+
+/*
+ * cert_StartExtensions
+ *
+ * NOTE: This interface changed significantly to remove knowledge
+ * about callers data structures (owner objects)
+ */
+void *
+cert_StartExtensions(void *owner, PRArenaPool *ownerArena,
+ void (*setExts)(void *object, CERTCertExtension **exts))
+{
+ PRArenaPool *arena;
+ extRec *handle;
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if ( !arena ) {
+ return(0);
+ }
+
+ handle = (extRec *)PORT_ArenaAlloc(arena, sizeof(extRec));
+ if ( !handle ) {
+ PORT_FreeArena(arena, PR_FALSE);
+ return(0);
+ }
+
+ handle->object = owner;
+ handle->ownerArena = ownerArena;
+ handle->setExts = setExts;
+
+ handle->arena = arena;
+ handle->head = 0;
+ handle->count = 0;
+
+ return(handle);
+}
+
+static unsigned char hextrue = 0xff;
+
+/*
+ * Note - assumes that data pointed to by oid->data will not move
+ */
+SECStatus
+CERT_AddExtensionByOID (void *exthandle, SECItem *oid, SECItem *value,
+ PRBool critical, PRBool copyData)
+{
+ CERTCertExtension *ext;
+ SECStatus rv;
+ extNode *node;
+ extRec *handle;
+
+ handle = (extRec *)exthandle;
+
+ /* allocate space for extension and list node */
+ ext = (CERTCertExtension*)PORT_ArenaZAlloc(handle->ownerArena,
+ sizeof(CERTCertExtension));
+ if ( !ext ) {
+ return(SECFailure);
+ }
+
+ node = (extNode*)PORT_ArenaAlloc(handle->arena, sizeof(extNode));
+ if ( !node ) {
+ return(SECFailure);
+ }
+
+ /* add to list */
+ node->next = handle->head;
+ handle->head = node;
+
+ /* point to ext struct */
+ node->ext = ext;
+
+ /* the object ID of the extension */
+ ext->id = *oid;
+
+ /* set critical field */
+ if ( critical ) {
+ ext->critical.data = (unsigned char*)&hextrue;
+ ext->critical.len = 1;
+ }
+
+ /* set the value */
+ if ( copyData ) {
+ rv = SECITEM_CopyItem(handle->ownerArena, &ext->value, value);
+ if ( rv ) {
+ return(SECFailure);
+ }
+ } else {
+ ext->value = *value;
+ }
+
+ handle->count++;
+
+ return(SECSuccess);
+
+}
+
+SECStatus
+CERT_AddExtension(void *exthandle, int idtag, SECItem *value,
+ PRBool critical, PRBool copyData)
+{
+ SECOidData *oid;
+
+ oid = SECOID_FindOIDByTag((SECOidTag)idtag);
+ if ( !oid ) {
+ return(SECFailure);
+ }
+
+ return(CERT_AddExtensionByOID(exthandle, &oid->oid, value, critical, copyData));
+}
+
+SECStatus
+CERT_EncodeAndAddExtension(void *exthandle, int idtag, void *value,
+ PRBool critical, const SEC_ASN1Template *atemplate)
+{
+ extRec *handle;
+ SECItem *encitem;
+
+ handle = (extRec *)exthandle;
+
+ encitem = SEC_ASN1EncodeItem(handle->ownerArena, NULL, value, atemplate);
+ if ( encitem == NULL ) {
+ return(SECFailure);
+ }
+
+ return CERT_AddExtension(exthandle, idtag, encitem, critical, PR_FALSE);
+}
+
+void
+PrepareBitStringForEncoding (SECItem *bitsmap, SECItem *value)
+{
+ unsigned char onebyte;
+ unsigned int i, len = 0;
+
+ /* to prevent warning on some platform at compile time */
+ onebyte = '\0';
+ /* Get the position of the right-most turn-on bit */
+ for (i = 0; i < (value->len ) * 8; ++i) {
+ if (i % 8 == 0)
+ onebyte = value->data[i/8];
+ if (onebyte & 0x80)
+ len = i;
+ onebyte <<= 1;
+
+ }
+ bitsmap->data = value->data;
+ /* Add one here since we work with base 1 */
+ bitsmap->len = len + 1;
+}
+
+SECStatus
+CERT_EncodeAndAddBitStrExtension (void *exthandle, int idtag,
+ SECItem *value, PRBool critical)
+{
+ SECItem bitsmap;
+
+ PrepareBitStringForEncoding (&bitsmap, value);
+ return (CERT_EncodeAndAddExtension
+ (exthandle, idtag, &bitsmap, critical, SEC_BitStringTemplate));
+}
+
+SECStatus
+CERT_FinishExtensions(void *exthandle)
+{
+ extRec *handle;
+ extNode *node;
+ CERTCertExtension **exts;
+ SECStatus rv = SECFailure;
+
+ handle = (extRec *)exthandle;
+
+ /* allocate space for extensions array */
+ exts = PORT_ArenaNewArray(handle->ownerArena, CERTCertExtension *,
+ handle->count + 1);
+ if (exts == NULL) {
+ goto loser;
+ }
+
+ /* put extensions in owner object and update its version number */
+
+#ifdef OLD
+ switch (handle->type) {
+ case CertificateExtensions:
+ handle->owner.cert->extensions = exts;
+ DER_SetUInteger (ownerArena, &(handle->owner.cert->version),
+ SEC_CERTIFICATE_VERSION_3);
+ break;
+ case CrlExtensions:
+ handle->owner.crl->extensions = exts;
+ DER_SetUInteger (ownerArena, &(handle->owner.crl->version),
+ SEC_CRL_VERSION_2);
+ break;
+ case OCSPRequestExtensions:
+ handle->owner.request->tbsRequest->requestExtensions = exts;
+ break;
+ case OCSPSingleRequestExtensions:
+ handle->owner.singleRequest->singleRequestExtensions = exts;
+ break;
+ case OCSPResponseSingleExtensions:
+ handle->owner.singleResponse->singleExtensions = exts;
+ break;
+ }
+#endif
+
+ handle->setExts(handle->object, exts);
+
+ /* update the version number */
+
+ /* copy each extension pointer */
+ node = handle->head;
+ while ( node ) {
+ *exts = node->ext;
+
+ node = node->next;
+ exts++;
+ }
+
+ /* terminate the array of extensions */
+ *exts = 0;
+
+ rv = SECSuccess;
+
+loser:
+ /* free working arena */
+ PORT_FreeArena(handle->arena, PR_FALSE);
+ return rv;
+}
+
+/*
+ * get the value of the Netscape Certificate Type Extension
+ */
+SECStatus
+CERT_FindBitStringExtension (CERTCertExtension **extensions, int tag,
+ SECItem *retItem)
+{
+ SECItem wrapperItem, tmpItem = {siBuffer,0};
+ SECStatus rv;
+ PRArenaPool *arena = NULL;
+
+ wrapperItem.data = NULL;
+ tmpItem.data = NULL;
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+
+ if ( ! arena ) {
+ return(SECFailure);
+ }
+
+ rv = cert_FindExtension(extensions, tag, &wrapperItem);
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ rv = SEC_QuickDERDecodeItem(arena, &tmpItem, SEC_BitStringTemplate,
+ &wrapperItem);
+
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ retItem->data = (unsigned char *)PORT_Alloc( ( tmpItem.len + 7 ) >> 3 );
+ if ( retItem->data == NULL ) {
+ goto loser;
+ }
+
+ PORT_Memcpy(retItem->data, tmpItem.data, ( tmpItem.len + 7 ) >> 3);
+ retItem->len = tmpItem.len;
+
+ rv = SECSuccess;
+ goto done;
+
+loser:
+ rv = SECFailure;
+
+done:
+ if ( arena ) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ if ( wrapperItem.data ) {
+ PORT_Free(wrapperItem.data);
+ }
+
+ return(rv);
+}
+
+PRBool
+cert_HasCriticalExtension (CERTCertExtension **extensions)
+{
+ CERTCertExtension **exts;
+ CERTCertExtension *ext = NULL;
+ PRBool hasCriticalExten = PR_FALSE;
+
+ exts = extensions;
+
+ if (exts) {
+ while ( *exts ) {
+ ext = *exts;
+ /* If the criticality is omitted, it's non-critical */
+ if (ext->critical.data && ext->critical.data[0] == 0xff) {
+ hasCriticalExten = PR_TRUE;
+ break;
+ }
+ exts++;
+ }
+ }
+ return (hasCriticalExten);
+}
+
+PRBool
+cert_HasUnknownCriticalExten (CERTCertExtension **extensions)
+{
+ CERTCertExtension **exts;
+ CERTCertExtension *ext = NULL;
+ PRBool hasUnknownCriticalExten = PR_FALSE;
+
+ exts = extensions;
+
+ if (exts) {
+ while ( *exts ) {
+ ext = *exts;
+ /* If the criticality is omitted, it's non-critical.
+ If an extension is critical, make sure that we know
+ how to process the extension.
+ */
+ if (ext->critical.data && ext->critical.data[0] == 0xff) {
+ if (SECOID_KnownCertExtenOID (&ext->id) == PR_FALSE) {
+ hasUnknownCriticalExten = PR_TRUE;
+ break;
+ }
+ }
+ exts++;
+ }
+ }
+ return (hasUnknownCriticalExten);
+}
diff --git a/security/nss/lib/certdb/certxutl.h b/security/nss/lib/certdb/certxutl.h
new file mode 100644
index 000000000..381226a43
--- /dev/null
+++ b/security/nss/lib/certdb/certxutl.h
@@ -0,0 +1,79 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+ * x.509 v3 certificate extension helper routines
+ *
+ */
+
+
+#ifndef _CERTXUTL_H_
+#define _CERTXUTL_H_
+
+#include "nspr.h"
+
+#ifdef OLD
+typedef enum {
+ CertificateExtensions,
+ CrlExtensions,
+ OCSPRequestExtensions,
+ OCSPSingleRequestExtensions,
+ OCSPResponseSingleExtensions
+} ExtensionsType;
+#endif
+
+extern PRBool
+cert_HasCriticalExtension (CERTCertExtension **extensions);
+
+extern SECStatus
+CERT_FindBitStringExtension (CERTCertExtension **extensions,
+ int tag, SECItem *retItem);
+extern void *
+cert_StartExtensions (void *owner, PLArenaPool *arena,
+ void (*setExts)(void *object, CERTCertExtension **exts));
+
+extern SECStatus
+cert_FindExtension (CERTCertExtension **extensions, int tag, SECItem *value);
+
+extern SECStatus
+cert_FindExtensionByOID (CERTCertExtension **extensions,
+ SECItem *oid, SECItem *value);
+
+extern SECStatus
+cert_GetExtenCriticality (CERTCertExtension **extensions,
+ int tag, PRBool *isCritical);
+
+extern PRBool
+cert_HasUnknownCriticalExten (CERTCertExtension **extensions);
+
+#endif
diff --git a/security/nss/lib/certdb/config.mk b/security/nss/lib/certdb/config.mk
new file mode 100644
index 000000000..0a00dc61e
--- /dev/null
+++ b/security/nss/lib/certdb/config.mk
@@ -0,0 +1,43 @@
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Netscape security libraries.
+#
+# The Initial Developer of the Original Code is Netscape
+# Communications Corporation. Portions created by Netscape are
+# Copyright (C) 1994-2000 Netscape Communications Corporation. All
+# Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the
+# terms of the GNU General Public License Version 2 or later (the
+# "GPL"), in which case the provisions of the GPL are applicable
+# instead of those above. If you wish to allow use of your
+# version of this file only under the terms of the GPL and not to
+# allow others to use your version of this file under the MPL,
+# indicate your decision by deleting the provisions above and
+# replace them with the notice and other provisions required by
+# the GPL. If you do not delete the provisions above, a recipient
+# may use your version of this file under either the MPL or the
+# GPL.
+#
+
+#
+# Override TARGETS variable so that only static libraries
+# are specifed as dependencies within rules.mk.
+#
+
+TARGETS = $(LIBRARY)
+SHARED_LIBRARY =
+IMPORT_LIBRARY =
+PROGRAM =
+
diff --git a/security/nss/lib/certdb/crl.c b/security/nss/lib/certdb/crl.c
new file mode 100644
index 000000000..72e0aa94e
--- /dev/null
+++ b/security/nss/lib/certdb/crl.c
@@ -0,0 +1,1950 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+ * Moved from secpkcs7.c
+ *
+ * $Id$
+ */
+
+#include "cert.h"
+#include "certi.h"
+#include "secder.h"
+#include "secasn1.h"
+#include "secoid.h"
+#include "certdb.h"
+#include "certxutl.h"
+#include "prtime.h"
+#include "secerr.h"
+#include "pk11func.h"
+#include "dev.h"
+#include "dev3hack.h"
+#include "nssbase.h"
+#ifdef USE_RWLOCK
+#include "nssrwlk.h"
+#endif
+
+const SEC_ASN1Template SEC_CERTExtensionTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTCertExtension) },
+ { SEC_ASN1_OBJECT_ID,
+ offsetof(CERTCertExtension,id) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, /* XXX DER_DEFAULT */
+ offsetof(CERTCertExtension,critical), },
+ { SEC_ASN1_OCTET_STRING,
+ offsetof(CERTCertExtension,value) },
+ { 0, }
+};
+
+static const SEC_ASN1Template SEC_CERTExtensionsTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_CERTExtensionTemplate}
+};
+
+/*
+ * XXX Also, these templates, especially the Krl/FORTEZZA ones, need to
+ * be tested; Lisa did the obvious translation but they still should be
+ * verified.
+ */
+
+const SEC_ASN1Template CERT_IssuerAndSNTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTIssuerAndSN) },
+ { SEC_ASN1_SAVE,
+ offsetof(CERTIssuerAndSN,derIssuer) },
+ { SEC_ASN1_INLINE,
+ offsetof(CERTIssuerAndSN,issuer),
+ CERT_NameTemplate },
+ { SEC_ASN1_INTEGER,
+ offsetof(CERTIssuerAndSN,serialNumber) },
+ { 0 }
+};
+
+static const SEC_ASN1Template cert_KrlEntryTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTCrlEntry) },
+ { SEC_ASN1_OCTET_STRING,
+ offsetof(CERTCrlEntry,serialNumber) },
+ { SEC_ASN1_UTC_TIME,
+ offsetof(CERTCrlEntry,revocationDate) },
+ { 0 }
+};
+
+static const SEC_ASN1Template cert_KrlTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTCrl) },
+ { SEC_ASN1_INLINE,
+ offsetof(CERTCrl,signatureAlg),
+ SECOID_AlgorithmIDTemplate },
+ { SEC_ASN1_SAVE,
+ offsetof(CERTCrl,derName) },
+ { SEC_ASN1_INLINE,
+ offsetof(CERTCrl,name),
+ CERT_NameTemplate },
+ { SEC_ASN1_UTC_TIME,
+ offsetof(CERTCrl,lastUpdate) },
+ { SEC_ASN1_UTC_TIME,
+ offsetof(CERTCrl,nextUpdate) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
+ offsetof(CERTCrl,entries),
+ cert_KrlEntryTemplate },
+ { 0 }
+};
+
+static const SEC_ASN1Template cert_SignedKrlTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTSignedCrl) },
+ { SEC_ASN1_SAVE,
+ offsetof(CERTSignedCrl,signatureWrap.data) },
+ { SEC_ASN1_INLINE,
+ offsetof(CERTSignedCrl,crl),
+ cert_KrlTemplate },
+ { SEC_ASN1_INLINE,
+ offsetof(CERTSignedCrl,signatureWrap.signatureAlgorithm),
+ SECOID_AlgorithmIDTemplate },
+ { SEC_ASN1_BIT_STRING,
+ offsetof(CERTSignedCrl,signatureWrap.signature) },
+ { 0 }
+};
+
+static const SEC_ASN1Template cert_CrlKeyTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTCrlKey) },
+ { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(CERTCrlKey,dummy) },
+ { SEC_ASN1_SKIP },
+ { SEC_ASN1_ANY, offsetof(CERTCrlKey,derName) },
+ { SEC_ASN1_SKIP_REST },
+ { 0 }
+};
+
+static const SEC_ASN1Template cert_CrlEntryTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTCrlEntry) },
+ { SEC_ASN1_INTEGER,
+ offsetof(CERTCrlEntry,serialNumber) },
+ { SEC_ASN1_UTC_TIME,
+ offsetof(CERTCrlEntry,revocationDate) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
+ offsetof(CERTCrlEntry, extensions),
+ SEC_CERTExtensionTemplate},
+ { 0 }
+};
+
+const SEC_ASN1Template CERT_CrlTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTCrl) },
+ { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof (CERTCrl, version) },
+ { SEC_ASN1_INLINE,
+ offsetof(CERTCrl,signatureAlg),
+ SECOID_AlgorithmIDTemplate },
+ { SEC_ASN1_SAVE,
+ offsetof(CERTCrl,derName) },
+ { SEC_ASN1_INLINE,
+ offsetof(CERTCrl,name),
+ CERT_NameTemplate },
+ { SEC_ASN1_UTC_TIME,
+ offsetof(CERTCrl,lastUpdate) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_UTC_TIME,
+ offsetof(CERTCrl,nextUpdate) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
+ offsetof(CERTCrl,entries),
+ cert_CrlEntryTemplate },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ SEC_ASN1_EXPLICIT | 0,
+ offsetof(CERTCrl,extensions),
+ SEC_CERTExtensionsTemplate},
+ { 0 }
+};
+
+const SEC_ASN1Template CERT_CrlTemplateNoEntries[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTCrl) },
+ { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof (CERTCrl, version) },
+ { SEC_ASN1_INLINE,
+ offsetof(CERTCrl,signatureAlg),
+ SECOID_AlgorithmIDTemplate },
+ { SEC_ASN1_SAVE,
+ offsetof(CERTCrl,derName) },
+ { SEC_ASN1_INLINE,
+ offsetof(CERTCrl,name),
+ CERT_NameTemplate },
+ { SEC_ASN1_UTC_TIME,
+ offsetof(CERTCrl,lastUpdate) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_UTC_TIME,
+ offsetof(CERTCrl,nextUpdate) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF |
+ SEC_ASN1_SKIP }, /* skip entries */
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ SEC_ASN1_EXPLICIT | 0,
+ offsetof(CERTCrl,extensions),
+ SEC_CERTExtensionsTemplate },
+ { 0 }
+};
+
+const SEC_ASN1Template CERT_CrlTemplateEntriesOnly[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTCrl) },
+ { SEC_ASN1_SKIP | SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL },
+ { SEC_ASN1_SKIP },
+ { SEC_ASN1_SKIP },
+ { SEC_ASN1_SKIP | SEC_ASN1_UTC_TIME },
+ { SEC_ASN1_SKIP | SEC_ASN1_OPTIONAL | SEC_ASN1_UTC_TIME },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
+ offsetof(CERTCrl,entries),
+ cert_CrlEntryTemplate }, /* decode entries */
+ { SEC_ASN1_SKIP_REST },
+ { 0 }
+};
+
+static const SEC_ASN1Template cert_SignedCrlTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTSignedCrl) },
+ { SEC_ASN1_SAVE,
+ offsetof(CERTSignedCrl,signatureWrap.data) },
+ { SEC_ASN1_INLINE,
+ offsetof(CERTSignedCrl,crl),
+ CERT_CrlTemplate },
+ { SEC_ASN1_INLINE,
+ offsetof(CERTSignedCrl,signatureWrap.signatureAlgorithm),
+ SECOID_AlgorithmIDTemplate },
+ { SEC_ASN1_BIT_STRING,
+ offsetof(CERTSignedCrl,signatureWrap.signature) },
+ { 0 }
+};
+
+static const SEC_ASN1Template cert_SignedCrlTemplateNoEntries[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTSignedCrl) },
+ { SEC_ASN1_SAVE,
+ offsetof(CERTSignedCrl,signatureWrap.data) },
+ { SEC_ASN1_INLINE,
+ offsetof(CERTSignedCrl,crl),
+ CERT_CrlTemplateNoEntries },
+ { SEC_ASN1_INLINE,
+ offsetof(CERTSignedCrl,signatureWrap.signatureAlgorithm),
+ SECOID_AlgorithmIDTemplate },
+ { SEC_ASN1_BIT_STRING,
+ offsetof(CERTSignedCrl,signatureWrap.signature) },
+ { 0 }
+};
+
+const SEC_ASN1Template CERT_SetOfSignedCrlTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, cert_SignedCrlTemplate },
+};
+
+/* Check the version of the CRL. If there is a critical extension in the crl
+ or crl entry, then the version must be v2. Otherwise, it should be v1. If
+ the crl contains critical extension(s), then we must recognized the extension's
+ OID.
+ */
+SECStatus cert_check_crl_version (CERTCrl *crl)
+{
+ CERTCrlEntry **entries;
+ CERTCrlEntry *entry;
+ PRBool hasCriticalExten = PR_FALSE;
+ SECStatus rv = SECSuccess;
+ int version;
+
+ /* CRL version is defaulted to v1 */
+ version = SEC_CRL_VERSION_1;
+ if (crl->version.data != 0)
+ version = (int)DER_GetUInteger (&crl->version);
+
+ if (version > SEC_CRL_VERSION_2) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ return (SECFailure);
+ }
+
+ /* Check the crl extensions for a critial extension. If one is found,
+ and the version is not v2, then we are done.
+ */
+ if (crl->extensions) {
+ hasCriticalExten = cert_HasCriticalExtension (crl->extensions);
+ if (hasCriticalExten) {
+ if (version != SEC_CRL_VERSION_2)
+ return (SECFailure);
+ /* make sure that there is no unknown critical extension */
+ if (cert_HasUnknownCriticalExten (crl->extensions) == PR_TRUE) {
+ PORT_SetError (SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
+ return (SECFailure);
+ }
+ }
+ }
+
+
+ if (crl->entries == NULL) {
+ return (SECSuccess);
+ }
+ /* Look in the crl entry extensions. If there is a critical extension,
+ then the crl version must be v2; otherwise, it should be v1.
+ */
+ entries = crl->entries;
+ while (*entries) {
+ entry = *entries;
+ if (entry->extensions) {
+ /* If there is a critical extension in the entries, then the
+ CRL must be of version 2. If we already saw a critical extension,
+ there is no need to check the version again.
+ */
+ if (hasCriticalExten == PR_FALSE) {
+ hasCriticalExten = cert_HasCriticalExtension (entry->extensions);
+ if (hasCriticalExten && version != SEC_CRL_VERSION_2) {
+ rv = SECFailure;
+ break;
+ }
+ }
+
+ /* For each entry, make sure that it does not contain an unknown
+ critical extension. If it does, we must reject the CRL since
+ we don't know how to process the extension.
+ */
+ if (cert_HasUnknownCriticalExten (entry->extensions) == PR_TRUE) {
+ PORT_SetError (SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
+ rv = SECFailure;
+ break;
+ }
+ }
+ ++entries;
+ }
+ if (rv == SECFailure)
+ return (rv);
+
+ return (SECSuccess);
+}
+
+/*
+ * Generate a database key, based on the issuer name from a
+ * DER crl.
+ */
+SECStatus
+CERT_KeyFromDERCrl(PRArenaPool *arena, SECItem *derCrl, SECItem *key)
+{
+ SECStatus rv;
+ CERTSignedData sd;
+ CERTCrlKey crlkey;
+
+ PORT_Memset (&sd, 0, sizeof (sd));
+ rv = SEC_ASN1DecodeItem (arena, &sd, CERT_SignedDataTemplate, derCrl);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+
+ PORT_Memset (&crlkey, 0, sizeof (crlkey));
+ rv = SEC_ASN1DecodeItem(arena, &crlkey, cert_CrlKeyTemplate, &sd.data);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+
+ key->len = crlkey.derName.len;
+ key->data = crlkey.derName.data;
+
+ return(SECSuccess);
+}
+
+#define GetOpaqueCRLFields(x) ((OpaqueCRLFields*)x->opaque)
+
+/*
+PRBool CERT_CRLIsInvalid(CERTSignedCrl* crl)
+{
+ OpaqueCRLFields* extended = NULL;
+
+ if (crl && (extended = (OpaqueCRLFields*) crl->opaque)) {
+ return extended->bad;
+ }
+ return PR_TRUE;
+}
+*/
+
+SECStatus CERT_CompleteCRLDecodeEntries(CERTSignedCrl* crl)
+{
+ SECStatus rv = SECSuccess;
+ SECItem* crldata = NULL;
+ OpaqueCRLFields* extended = NULL;
+
+ if ( (!crl) ||
+ (!(extended = (OpaqueCRLFields*) crl->opaque)) ) {
+ rv = SECFailure;
+ } else {
+ if (PR_FALSE == extended->partial) {
+ /* the CRL has already been fully decoded */
+ return SECSuccess;
+ }
+ if (PR_TRUE == extended->badEntries) {
+ /* the entries decoding already failed */
+ return SECFailure;
+ }
+ crldata = &crl->signatureWrap.data;
+ if (!crldata) {
+ rv = SECFailure;
+ }
+ }
+
+ if (SECSuccess == rv) {
+ rv = SEC_QuickDERDecodeItem(crl->arena,
+ &crl->crl,
+ CERT_CrlTemplateEntriesOnly,
+ crldata);
+ if (SECSuccess == rv) {
+ extended->partial = PR_FALSE; /* successful decode, avoid
+ decoding again */
+ } else {
+ extended->bad = PR_TRUE;
+ extended->badEntries = PR_TRUE;
+ /* cache the decoding failure. If it fails the first time,
+ it will fail again, which will grow the arena and leak
+ memory, so we want to avoid it */
+ }
+ }
+ return rv;
+}
+
+/*
+ * take a DER CRL or KRL and decode it into a CRL structure
+ * allow reusing the input DER without making a copy
+ */
+CERTSignedCrl *
+CERT_DecodeDERCrlWithFlags(PRArenaPool *narena, SECItem *derSignedCrl,
+ int type, PRInt32 options)
+{
+ PRArenaPool *arena;
+ CERTSignedCrl *crl;
+ SECStatus rv;
+ OpaqueCRLFields* extended = NULL;
+ const SEC_ASN1Template* crlTemplate = cert_SignedCrlTemplate;
+
+ /* make a new arena */
+ if (narena == NULL) {
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if ( !arena ) {
+ return NULL;
+ }
+ } else {
+ arena = narena;
+ }
+
+ /* allocate the CRL structure */
+ crl = (CERTSignedCrl *)PORT_ArenaZAlloc(arena, sizeof(CERTSignedCrl));
+ if ( !crl ) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ goto loser;
+ }
+
+ crl->arena = arena;
+
+ /* allocate opaque fields */
+ crl->opaque = (void*)PORT_ArenaZAlloc(arena, sizeof(OpaqueCRLFields));
+ if ( !crl->opaque ) {
+ goto loser;
+ }
+ extended = (OpaqueCRLFields*) crl->opaque;
+
+ if (options & CRL_DECODE_DONT_COPY_DER) {
+ crl->derCrl = derSignedCrl; /* DER is not copied . The application
+ must keep derSignedCrl until it
+ destroys the CRL */
+ } else {
+ crl->derCrl = (SECItem *)PORT_ArenaZAlloc(arena,sizeof(SECItem));
+ if (crl->derCrl == NULL) {
+ goto loser;
+ }
+ rv = SECITEM_CopyItem(arena, crl->derCrl, derSignedCrl);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+
+ /* Save the arena in the inner crl for CRL extensions support */
+ crl->crl.arena = arena;
+ if (options & CRL_DECODE_SKIP_ENTRIES) {
+ crlTemplate = cert_SignedCrlTemplateNoEntries;
+ extended->partial = PR_TRUE;
+ }
+
+ /* decode the CRL info */
+ switch (type) {
+ case SEC_CRL_TYPE:
+ rv = SEC_QuickDERDecodeItem(arena, crl, crlTemplate, crl->derCrl);
+ if (rv != SECSuccess) {
+ extended->badDER = PR_TRUE;
+ break;
+ }
+ /* check for critical extentions */
+ rv = cert_check_crl_version (&crl->crl);
+ if (rv != SECSuccess) {
+ extended->badExtensions = PR_TRUE;
+ }
+ break;
+
+ case SEC_KRL_TYPE:
+ rv = SEC_QuickDERDecodeItem
+ (arena, crl, cert_SignedKrlTemplate, derSignedCrl);
+ break;
+ default:
+ rv = SECFailure;
+ break;
+ }
+
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ crl->referenceCount = 1;
+
+ return(crl);
+
+loser:
+ if (options & CRL_DECODE_KEEP_BAD_CRL) {
+ extended->bad = PR_TRUE;
+ crl->referenceCount = 1;
+ return(crl);
+ }
+
+ if ((narena == NULL) && arena ) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ return(0);
+}
+
+/*
+ * take a DER CRL or KRL and decode it into a CRL structure
+ */
+CERTSignedCrl *
+CERT_DecodeDERCrl(PRArenaPool *narena, SECItem *derSignedCrl, int type)
+{
+ return CERT_DecodeDERCrlWithFlags(narena, derSignedCrl, type, CRL_DECODE_DEFAULT_OPTIONS);
+}
+
+/*
+ * Lookup a CRL in the databases. We mirror the same fast caching data base
+ * caching stuff used by certificates....?
+ * return values :
+ *
+ * SECSuccess means we got a valid DER CRL (passed in "decoded"), or no CRL at all
+ *
+ * SECFailure means we got a fatal error - most likely, we found a CRL,
+ * and it failed decoding, or there was an out of memory error. Do NOT ignore
+ * it and specifically do NOT treat it the same as having no CRL, as this
+ * can compromise security !!! Ideally, you should treat this case as if you
+ * received a "catch-all" CRL where all certs you were looking up are
+ * considered to be revoked
+ */
+static SECStatus
+SEC_FindCrlByKeyOnSlot(PK11SlotInfo *slot, SECItem *crlKey, int type,
+ CERTSignedCrl** decoded, PRInt32 decodeoptions)
+{
+ SECStatus rv = SECSuccess;
+ CERTSignedCrl *crl = NULL;
+ SECItem *derCrl = NULL;
+ CK_OBJECT_HANDLE crlHandle = 0;
+ char *url = NULL;
+ int nsserror;
+
+ PORT_Assert(decoded);
+ if (!decoded) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (slot) {
+ PK11_ReferenceSlot(slot);
+ }
+
+ /* XXX it would be really useful to be able to fetch the CRL directly into an
+ arena. This would avoid a copy later on in the decode step */
+ PORT_SetError(0);
+ derCrl = PK11_FindCrlByName(&slot, &crlHandle, crlKey, type, &url);
+ if (derCrl == NULL) {
+ /* if we had a problem other than the CRL just didn't exist, return
+ * a failure to the upper level */
+ nsserror = PORT_GetError();
+ if ((nsserror != 0) && (nsserror != SEC_ERROR_CRL_NOT_FOUND)) {
+ rv = SECFailure;
+ }
+ goto loser;
+ }
+ PORT_Assert(crlHandle != CK_INVALID_HANDLE);
+
+ crl = CERT_DecodeDERCrlWithFlags(NULL, derCrl, type, decodeoptions);
+ if (crl) {
+ crl->slot = slot;
+ slot = NULL; /* adopt it */
+ crl->pkcs11ID = crlHandle;
+ if (url) {
+ crl->url = PORT_ArenaStrdup(crl->arena,url);
+ }
+ } else {
+ rv = SECFailure;
+ }
+
+ if (url) {
+ PORT_Free(url);
+ }
+
+loser:
+ if (slot) {
+ PK11_FreeSlot(slot);
+ }
+
+ if (derCrl) {
+ /* destroy the DER, unless a decoded CRL was returned with DER
+ allocated on the heap. This is solely for cache purposes */
+ if (crl && (decodeoptions & CRL_DECODE_DONT_COPY_DER)) {
+ /* mark the DER as having come from the heap instead of the
+ arena, so it can be destroyed */
+ GetOpaqueCRLFields(crl)->heapDER = PR_TRUE;
+ } else {
+ SECITEM_FreeItem(derCrl, PR_TRUE);
+ }
+ }
+
+ *decoded = crl;
+
+ return rv;
+}
+
+SECStatus SEC_DestroyCrl(CERTSignedCrl *crl);
+
+CERTSignedCrl *
+crl_storeCRL (PK11SlotInfo *slot,char *url,
+ CERTSignedCrl *newCrl, SECItem *derCrl, int type)
+{
+ CERTSignedCrl *oldCrl = NULL, *crl = NULL;
+ PRBool deleteOldCrl = PR_FALSE;
+ CK_OBJECT_HANDLE crlHandle;
+
+ PORT_Assert(newCrl);
+ PORT_Assert(derCrl);
+
+ /* we can't use the cache here because we must look in the same
+ token */
+ SEC_FindCrlByKeyOnSlot(slot, &newCrl->crl.derName, type,
+ &oldCrl, CRL_DECODE_SKIP_ENTRIES);
+
+ /* if there is an old crl on the token, make sure the one we are
+ installing is newer. If not, exit out, otherwise delete the
+ old crl.
+ */
+ if (oldCrl != NULL) {
+ /* if it's already there, quietly continue */
+ if (SECITEM_CompareItem(newCrl->derCrl, oldCrl->derCrl)
+ == SECEqual) {
+ crl = newCrl;
+ crl->slot = PK11_ReferenceSlot(slot);
+ crl->pkcs11ID = oldCrl->pkcs11ID;
+ goto done;
+ }
+ if (!SEC_CrlIsNewer(&newCrl->crl,&oldCrl->crl)) {
+
+ if (type == SEC_CRL_TYPE) {
+ PORT_SetError(SEC_ERROR_OLD_CRL);
+ } else {
+ PORT_SetError(SEC_ERROR_OLD_KRL);
+ }
+
+ goto done;
+ }
+
+ if ((SECITEM_CompareItem(&newCrl->crl.derName,
+ &oldCrl->crl.derName) != SECEqual) &&
+ (type == SEC_KRL_TYPE) ) {
+
+ PORT_SetError(SEC_ERROR_CKL_CONFLICT);
+ goto done;
+ }
+
+ /* if we have a url in the database, use that one */
+ if (oldCrl->url) {
+ url = oldCrl->url;
+ }
+
+ /* really destroy this crl */
+ /* first drum it out of the permanment Data base */
+ deleteOldCrl = PR_TRUE;
+ }
+
+ /* invalidate CRL cache for this issuer */
+ CERT_CRLCacheRefreshIssuer(NULL, &newCrl->crl.derName);
+ /* Write the new entry into the data base */
+ crlHandle = PK11_PutCrl(slot, derCrl, &newCrl->crl.derName, url, type);
+ if (crlHandle != CK_INVALID_HANDLE) {
+ crl = newCrl;
+ crl->slot = PK11_ReferenceSlot(slot);
+ crl->pkcs11ID = crlHandle;
+ if (url) {
+ crl->url = PORT_ArenaStrdup(crl->arena,url);
+ }
+ }
+
+done:
+ if (oldCrl) {
+ if (deleteOldCrl && crlHandle != CK_INVALID_HANDLE) {
+ SEC_DeletePermCRL(oldCrl);
+ }
+ SEC_DestroyCrl(oldCrl);
+ }
+
+ return crl;
+}
+
+/*
+ *
+ * create a new CRL from DER material.
+ *
+ * The signature on this CRL must be checked before you
+ * load it. ???
+ */
+CERTSignedCrl *
+SEC_NewCrl(CERTCertDBHandle *handle, char *url, SECItem *derCrl, int type)
+{
+ CERTSignedCrl* retCrl = NULL;
+ PK11SlotInfo* slot = PK11_GetInternalKeySlot();
+ retCrl = PK11_ImportCRL(slot, derCrl, url, type, NULL,
+ CRL_IMPORT_BYPASS_CHECKS, NULL, CRL_DECODE_DEFAULT_OPTIONS);
+ PK11_FreeSlot(slot);
+
+ return retCrl;
+}
+
+CERTSignedCrl *
+SEC_FindCrlByDERCert(CERTCertDBHandle *handle, SECItem *derCrl, int type)
+{
+ PRArenaPool *arena;
+ SECItem crlKey;
+ SECStatus rv;
+ CERTSignedCrl *crl = NULL;
+
+ /* create a scratch arena */
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if ( arena == NULL ) {
+ return(NULL);
+ }
+
+ /* extract the database key from the cert */
+ rv = CERT_KeyFromDERCrl(arena, derCrl, &crlKey);
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ /* find the crl */
+ crl = SEC_FindCrlByName(handle, &crlKey, type);
+
+loser:
+ PORT_FreeArena(arena, PR_FALSE);
+ return(crl);
+}
+
+CERTSignedCrl* SEC_DupCrl(CERTSignedCrl* acrl)
+{
+ if (acrl)
+ {
+ PR_AtomicIncrement(&acrl->referenceCount);
+ return acrl;
+ }
+ return NULL;
+}
+
+SECStatus
+SEC_DestroyCrl(CERTSignedCrl *crl)
+{
+ if (crl) {
+ if (PR_AtomicDecrement(&crl->referenceCount) < 1) {
+ if (crl->slot) {
+ PK11_FreeSlot(crl->slot);
+ }
+ if (PR_TRUE == GetOpaqueCRLFields(crl)->heapDER) {
+ SECITEM_FreeItem(crl->derCrl, PR_TRUE);
+ }
+ PORT_FreeArena(crl->arena, PR_FALSE);
+ }
+ }
+ return SECSuccess;
+}
+
+SECStatus
+SEC_LookupCrls(CERTCertDBHandle *handle, CERTCrlHeadNode **nodes, int type)
+{
+ CERTCrlHeadNode *head;
+ PRArenaPool *arena = NULL;
+ SECStatus rv;
+
+ *nodes = NULL;
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if ( arena == NULL ) {
+ return SECFailure;
+ }
+
+ /* build a head structure */
+ head = (CERTCrlHeadNode *)PORT_ArenaAlloc(arena, sizeof(CERTCrlHeadNode));
+ head->arena = arena;
+ head->first = NULL;
+ head->last = NULL;
+ head->dbhandle = handle;
+
+ /* Look up the proper crl types */
+ *nodes = head;
+
+ rv = PK11_LookupCrls(head, type, NULL);
+
+ if (rv != SECSuccess) {
+ if ( arena ) {
+ PORT_FreeArena(arena, PR_FALSE);
+ *nodes = NULL;
+ }
+ }
+
+ return rv;
+}
+
+/* These functions simply return the address of the above-declared templates.
+** This is necessary for Windows DLLs. Sigh.
+*/
+SEC_ASN1_CHOOSER_IMPLEMENT(CERT_IssuerAndSNTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CrlTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SetOfSignedCrlTemplate)
+
+/*
+** Pre-allocator hash allocator ops.
+*/
+static void * PR_CALLBACK
+PreAllocTable(void *pool, PRSize size)
+{
+ PreAllocator* alloc = (PreAllocator*)pool;
+ PR_ASSERT(alloc);
+ if (!alloc)
+ {
+ /* no allocator, or buffer full */
+ return NULL;
+ }
+ if (size > (alloc->len - alloc->used))
+ {
+ alloc->extra += size;
+ return PORT_ArenaAlloc(alloc->arena, size);
+ }
+ alloc->used += size;
+ return (char*) alloc->data + alloc->used - size;
+}
+
+static void PR_CALLBACK
+PreFreeTable(void *pool, void *item)
+{
+}
+
+static PLHashEntry * PR_CALLBACK
+PreAllocEntry(void *pool, const void *key)
+{
+ return PreAllocTable(pool, sizeof(PLHashEntry));
+}
+
+static void PR_CALLBACK
+PreFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
+{
+}
+
+static PLHashAllocOps preAllocOps = {
+ PreAllocTable, PreFreeTable,
+ PreAllocEntry, PreFreeEntry
+};
+
+void PreAllocator_Destroy(PreAllocator* PreAllocator)
+{
+ if (!PreAllocator)
+ {
+ return;
+ }
+ if (PreAllocator->arena)
+ {
+ PORT_FreeArena(PreAllocator->arena, PR_TRUE);
+ }
+ if (PreAllocator->data)
+ {
+ PORT_Free(PreAllocator->data);
+ }
+ PORT_Free(PreAllocator);
+}
+
+PreAllocator* PreAllocator_Create(PRSize size)
+{
+ PreAllocator prebuffer;
+ PreAllocator* prepointer = NULL;
+ memset(&prebuffer, 0, sizeof(PreAllocator));
+ prebuffer.len = size;
+ prebuffer.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ PR_ASSERT(prebuffer.arena);
+ if (!prebuffer.arena) {
+ PreAllocator_Destroy(&prebuffer);
+ return NULL;
+ }
+ if (prebuffer.len) {
+ prebuffer.data = PR_Malloc(prebuffer.len);
+ if (!prebuffer.data) {
+ PreAllocator_Destroy(&prebuffer);
+ return NULL;
+ }
+ } else {
+ prebuffer.data = NULL;
+ }
+ prepointer = (PreAllocator*)PR_Malloc(sizeof(PreAllocator));
+ if (!prepointer) {
+ PreAllocator_Destroy(&prebuffer);
+ return NULL;
+ }
+ *prepointer = prebuffer;
+ return prepointer;
+}
+
+static CRLCache crlcache = { NULL, NULL };
+
+static PRBool crlcache_initialized = PR_FALSE;
+
+/* this needs to be called at NSS initialization time */
+
+SECStatus InitCRLCache(void)
+{
+ if (PR_FALSE == crlcache_initialized)
+ {
+ PR_ASSERT(NULL == crlcache.lock);
+ crlcache.lock = PR_NewLock();
+ if (!crlcache.lock)
+ {
+ return SECFailure;
+ }
+ PR_ASSERT(NULL == crlcache.issuers);
+ crlcache.issuers = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
+ PL_CompareValues, NULL, NULL);
+ if (!crlcache.issuers)
+ {
+ PR_DestroyLock(crlcache.lock);
+ crlcache.lock = NULL;
+ return SECFailure;
+ }
+ crlcache_initialized = PR_TRUE;
+ return SECSuccess;
+ }
+ else
+ {
+ PR_ASSERT(crlcache.lock);
+ PR_ASSERT(crlcache.issuers);
+ if ( (NULL == crlcache.lock) || (NULL == crlcache.issuers) )
+ {
+ return SECFailure;
+ }
+ else
+ {
+ return SECSuccess;
+ }
+ }
+}
+
+SECStatus DPCache_Destroy(CRLDPCache* cache)
+{
+ PRUint32 i = 0;
+ PR_ASSERT(cache);
+ if (!cache) {
+ return SECFailure;
+ }
+ if (cache->lock)
+ {
+#ifdef USE_RWLOCK
+ NSSRWLock_Destroy(cache->lock);
+#else
+ PR_DestroyLock(cache->lock);
+#endif
+ }
+ /* destroy all our CRL objects */
+ for (i=0;i<cache->ncrls;i++)
+ {
+ SEC_DestroyCrl(cache->crls[i]);
+ }
+ /* free the array of CRLs */
+ if (cache->crls)
+ {
+ PR_Free(cache->crls);
+ }
+ /* destroy the hash table */
+ if (cache->entries)
+ {
+ PL_HashTableDestroy(cache->entries);
+ }
+ /* free the pre buffer */
+ if (cache->prebuffer)
+ {
+ PreAllocator_Destroy(cache->prebuffer);
+ }
+ /* destroy the cert */
+ if (cache->issuer)
+ {
+ CERT_DestroyCertificate(cache->issuer);
+ }
+ /* free the subject */
+ if (cache->subject)
+ {
+ SECITEM_FreeItem(cache->subject, PR_TRUE);
+ }
+ /* free the distribution points */
+ if (cache->distributionPoint)
+ {
+ SECITEM_FreeItem(cache->distributionPoint, PR_TRUE);
+ }
+ return SECSuccess;
+}
+
+SECStatus IssuerCache_Destroy(CRLIssuerCache* cache)
+{
+ PORT_Assert(cache);
+ if (!cache)
+ {
+ return SECFailure;
+ }
+#if 0
+ /* XCRL */
+ if (cache->lock)
+ {
+ NSSRWLock_Destroy(cache->lock);
+ }
+ if (cache->issuer)
+ {
+ CERT_DestroyCertificate(cache->issuer);
+ }
+#endif
+ /* free the subject */
+ if (cache->subject)
+ {
+ SECITEM_FreeItem(cache->subject, PR_TRUE);
+ }
+ DPCache_Destroy(&cache->dp);
+ PR_Free(cache);
+ return SECSuccess;
+}
+
+PRIntn PR_CALLBACK FreeIssuer(PLHashEntry *he, PRIntn i, void *arg)
+{
+ CRLIssuerCache* issuer = NULL;
+ PR_ASSERT(he);
+ if (!he) {
+ return HT_ENUMERATE_NEXT;
+ }
+ issuer = (CRLIssuerCache*) he->value;
+ PR_ASSERT(issuer);
+ if (issuer) {
+ IssuerCache_Destroy(issuer);
+ }
+ return HT_ENUMERATE_NEXT;
+}
+
+SECStatus ShutdownCRLCache(void)
+{
+ if (!crlcache.lock || !crlcache.issuers)
+ {
+ return SECFailure;
+ }
+ /* empty the cache */
+ PL_HashTableEnumerateEntries(crlcache.issuers, &FreeIssuer, NULL);
+ PL_HashTableDestroy(crlcache.issuers);
+ crlcache.issuers = NULL;
+ PR_DestroyLock(crlcache.lock);
+ crlcache.lock = NULL;
+ crlcache_initialized = PR_FALSE;
+ return SECSuccess;
+}
+
+SECStatus DPCache_AddCRL(CRLDPCache* cache, CERTSignedCrl* crl)
+{
+ CERTSignedCrl** newcrls = NULL;
+ PORT_Assert(cache);
+ PORT_Assert(crl);
+ if (!cache || !crl) {
+ return SECFailure;
+ }
+
+ newcrls = (CERTSignedCrl**)PORT_Realloc(cache->crls,
+ (cache->ncrls+1)*sizeof(CERTSignedCrl*));
+ if (!newcrls) {
+ return SECFailure;
+ }
+ cache->crls = newcrls;
+ cache->ncrls++;
+ cache->crls[cache->ncrls-1] = crl;
+ return SECSuccess;
+}
+
+SECStatus DPCache_Cleanup(CRLDPCache* cache)
+{
+ /* remove deleted CRLs from memory */
+ PRUint32 i = 0;
+ PORT_Assert(cache);
+ if (!cache) {
+ return SECFailure;
+ }
+ for (i=0;i<cache->ncrls;i++) {
+ CERTSignedCrl* acrl = cache->crls[i];
+ if (acrl && (PR_TRUE == GetOpaqueCRLFields(acrl)->deleted)) {
+ cache->crls[i] = cache->crls[cache->ncrls-1];
+ cache->crls[cache->ncrls-1] = NULL;
+ cache->ncrls--;
+ }
+ }
+ return SECSuccess;
+}
+
+PRBool CRLStillExists(CERTSignedCrl* crl)
+{
+ NSSItem newsubject;
+ SECItem subject;
+ CK_ULONG crl_class;
+ PRStatus status;
+ PK11SlotInfo* slot = NULL;
+ nssCryptokiObject instance;
+ NSSArena* arena;
+ PRBool xstatus = PR_TRUE;
+ SECItem* oldSubject = NULL;
+
+ PORT_Assert(crl);
+ if (!crl) {
+ return PR_FALSE;
+ }
+ slot = crl->slot;
+ PORT_Assert(slot);
+ if (!slot) {
+ return PR_FALSE;
+ }
+ oldSubject = &crl->crl.derName;
+ PR_ASSERT(oldSubject);
+ if (!oldSubject) {
+ return PR_FALSE;
+ }
+
+ /* query subject and type attributes in order to determine if the
+ object has been deleted */
+
+ /* first, make an nssCryptokiObject */
+ instance.handle = crl->pkcs11ID;
+ PORT_Assert(instance.handle);
+ if (!instance.handle) {
+ return PR_FALSE;
+ }
+ instance.token = PK11Slot_GetNSSToken(slot);
+ PORT_Assert(instance.token);
+ if (!instance.token) {
+ return PR_FALSE;
+ }
+ instance.isTokenObject = PR_TRUE;
+ instance.label = NULL;
+
+ arena = NSSArena_Create();
+ PORT_Assert(arena);
+ if (!arena) {
+ return PR_FALSE;
+ }
+
+ status = nssCryptokiCRL_GetAttributes(&instance,
+ NULL, /* XXX sessionOpt */
+ arena,
+ NULL,
+ &newsubject, /* subject */
+ &crl_class, /* class */
+ NULL,
+ NULL);
+ if (PR_SUCCESS == status) {
+ subject.data = newsubject.data;
+ subject.len = newsubject.size;
+ if (SECITEM_CompareItem(oldSubject, &subject) != SECEqual) {
+ xstatus = PR_FALSE;
+ }
+ if (CKO_NETSCAPE_CRL != crl_class) {
+ xstatus = PR_FALSE;
+ }
+ } else {
+ xstatus = PR_FALSE;
+ }
+ NSSArena_Destroy(arena);
+ return xstatus;
+}
+
+SECStatus DPCache_Refresh(CRLDPCache* cache, CERTSignedCrl* crlobject,
+ void* wincx)
+{
+ SECStatus rv = SECSuccess;
+ /* Check if it is an invalid CRL
+ if we got a bad CRL, we want to cache it in order to avoid
+ subsequent fetches of this same identical bad CRL. We set
+ the cache to the invalid state to ensure that all certs
+ on this DP are considered revoked from now on. The cache
+ object will remain in this state until the bad CRL object
+ is removed from the token it was fetched from. If the cause
+ of the failure is that we didn't have the issuer cert to
+ verify the signature, this state can be cleared when
+ the issuer certificate becomes available if that causes the
+ signature to verify */
+
+ if (PR_TRUE == GetOpaqueCRLFields(crlobject)->bad) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ cache->invalid |= CRL_CACHE_INVALID_CRLS;
+ return SECSuccess;
+ } else {
+ SECStatus signstatus = SECFailure;
+ if (cache->issuer) {
+ int64 issuingDate = 0;
+ signstatus = DER_UTCTimeToTime(&issuingDate, &crlobject->crl.lastUpdate);
+ if (SECSuccess == signstatus) {
+ signstatus = CERT_VerifySignedData(&crlobject->signatureWrap,
+ cache->issuer, issuingDate, wincx);
+ }
+ }
+ if (SECSuccess != signstatus) {
+ if (!cache->issuer) {
+ /* we tried to verify without an issuer cert . This is
+ because this CRL came through a call to SEC_FindCrlByName.
+ So we don't cache this verification failure. We'll try
+ to verify the CRL again when a certificate from that issuer
+ becomes available */
+ GetOpaqueCRLFields(crlobject)->unverified = PR_TRUE;
+ } else {
+ GetOpaqueCRLFields(crlobject)->unverified = PR_FALSE;
+ }
+ PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE);
+ cache->invalid |= CRL_CACHE_INVALID_CRLS;
+ return SECSuccess;
+ } else {
+ GetOpaqueCRLFields(crlobject)->unverified = PR_FALSE;
+ }
+ }
+
+ /* complete the entry decoding */
+ rv = CERT_CompleteCRLDecodeEntries(crlobject);
+ if (SECSuccess == rv) {
+ /* XCRL : if this is a delta, add it to the hash table */
+ /* for now, always build the hash table from the full CRL */
+ CERTCrlEntry** crlEntry = NULL;
+ PRUint32 numEntries = 0;
+ if (cache->entries) {
+ /* we already have a hash table, destroy it */
+ PL_HashTableDestroy(cache->entries);
+ cache->entries = NULL;
+ }
+ /* also destroy the PreAllocator */
+ if (cache->prebuffer)
+ {
+ PreAllocator_Destroy(cache->prebuffer);
+ cache->prebuffer = NULL;
+ }
+ /* count CRL entries so we can pre-allocate space for hash table entries */
+ for (crlEntry = crlobject->crl.entries; crlEntry && *crlEntry; crlEntry++) {
+ numEntries++;
+ }
+ cache->prebuffer = PreAllocator_Create(numEntries*sizeof(PLHashEntry));
+ PR_ASSERT(cache->prebuffer);
+ if (cache->prebuffer) {
+ /* create a new hash table */
+ cache->entries = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
+ PL_CompareValues, &preAllocOps, cache->prebuffer);
+ }
+ PR_ASSERT(cache->entries);
+ if (!cache->entries) {
+ rv = SECFailure;
+ }
+ if (SECSuccess == rv) {
+ /* add all serial numbers to the hash table */
+ for (crlEntry = crlobject->crl.entries; crlEntry && *crlEntry; crlEntry++) {
+ PL_HashTableAdd(cache->entries, &(*crlEntry)->serialNumber, *crlEntry);
+ }
+ cache->full = crlobject;
+ cache->invalid = 0; /* valid cache */
+ } else {
+ cache->invalid |= CRL_CACHE_OUT_OF_MEMORY;
+ }
+ } else {
+ cache->invalid |= CRL_CACHE_INVALID_CRLS;
+ }
+ return rv;
+}
+
+void DPCache_Empty(CRLDPCache* cache)
+{
+ PRUint32 i;
+ PR_ASSERT(cache);
+ if (!cache)
+ {
+ return;
+ }
+ cache->full = NULL;
+
+ cache->invalid = 0;
+
+ if (cache->entries) {
+ /* we already have a hash table, destroy it */
+ PL_HashTableDestroy(cache->entries);
+ cache->entries = NULL;
+ }
+ /* also destroy the PreAllocator */
+ if (cache->prebuffer)
+ {
+ PreAllocator_Destroy(cache->prebuffer);
+ cache->prebuffer = NULL;
+ }
+
+ for (i=0;i<cache->ncrls;i++)
+ {
+ CERTSignedCrl* crl = cache->crls[i];
+ if (crl)
+ {
+ GetOpaqueCRLFields(crl)->deleted = PR_TRUE;
+ }
+ }
+}
+
+SECStatus DPCache_Fetch(CRLDPCache* cache, void* wincx)
+{
+ SECStatus rv = SECSuccess;
+ CERTSignedCrl* crlobject = NULL;
+ PRUint32 i=0;
+ /* XCRL For now, we can only get one full CRL. In the future, we'll be able to
+ find more than one object, because of multiple tokens and deltas */
+ rv = SEC_FindCrlByKeyOnSlot(NULL, cache->subject, SEC_CRL_TYPE,
+ &crlobject, CRL_DECODE_DONT_COPY_DER |
+ CRL_DECODE_SKIP_ENTRIES |
+ CRL_DECODE_KEEP_BAD_CRL);
+ /* if this function fails, something very wrong happened, such as an out
+ of memory error during CRL decoding. We don't want to proceed and must
+ mark the cache object invalid */
+ if (SECFailure == rv) {
+ cache->invalid |= CRL_CACHE_LAST_FETCH_FAILED;
+ } else {
+ cache->invalid &= (~CRL_CACHE_LAST_FETCH_FAILED);
+ }
+
+ if ((SECSuccess == rv) && (!crlobject)) {
+ /* no CRL was found. This is OK */
+ DPCache_Empty(cache);
+ return SECSuccess;
+ }
+
+ /* now check if we already have a binary equivalent DER CRL */
+ for (i=0;i<cache->ncrls;i++) {
+ CERTSignedCrl* existing = cache->crls[i];
+ if (existing && (SECEqual == SECITEM_CompareItem(existing->derCrl, crlobject->derCrl))) {
+ /* yes. Has the matching CRL been marked deleted ? */
+ if (PR_TRUE == GetOpaqueCRLFields(crlobject)->deleted) {
+ /* Yes. Just replace the CK object ID and slot in the existing object.
+ This avoids an unnecessary signature verification & entry decode */
+ /* XCRL we'll need to lock the CRL here in the future for iCRLs that are
+ shared between multiple CAs */
+ existing->pkcs11ID = crlobject->pkcs11ID;
+ PK11_FreeSlot(existing->slot); /* release reference to old
+ CRL slot */
+ existing->slot = crlobject->slot; /* adopt new CRL slot */
+ crlobject->slot = NULL; /* clear slot to avoid double-freeing it
+ during CRL destroy */
+ rv = SEC_DestroyCrl(crlobject);
+ PORT_Assert(SECSuccess == rv);
+ return rv;
+ } else {
+ /* We got an identical CRL from a different token.
+ Throw it away. */
+ return SEC_DestroyCrl(crlobject);
+ }
+ }
+ }
+
+ /* add the CRL to our array */
+ if (SECSuccess == rv) {
+ rv = DPCache_AddCRL(cache, crlobject);
+ }
+
+ /* update the cache with this new CRL */
+ if (SECSuccess == rv) {
+ rv = DPCache_Refresh(cache, crlobject, wincx);
+ }
+ return rv;
+}
+
+SECStatus DPCache_Lookup(CRLDPCache* cache, SECItem* sn, CERTCrlEntry** returned)
+{
+ CERTSignedCrl* crl = NULL;
+ CERTCrlEntry* acrlEntry = NULL;
+ if (!cache || !sn) {
+ /* no cache or SN to look up, this is bad */
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (0 != cache->invalid) {
+ /* the cache contains a bad CRL, consider all certs revoked
+ as a security measure */
+ PORT_SetError(SEC_ERROR_CRL_INVALID);
+ return SECFailure;
+ }
+ if (!cache->full) {
+ /* no CRL means no entry to return, but this is OK */
+ *returned = NULL;
+ return SECSuccess;
+ }
+ crl = cache->full;
+ PR_ASSERT(cache->entries);
+ if (!cache->entries)
+ {
+ return SECFailure;
+ }
+ acrlEntry = PL_HashTableLookup(cache->entries, (void*)sn);
+ if (acrlEntry)
+ {
+ *returned = acrlEntry;
+ }
+ return SECSuccess;
+}
+
+#ifdef USE_RWLOCK
+
+#define DPCache_LockWrite() { \
+ if (readlocked){ \
+ NSSRWLock_UnlockRead(cache->lock); \
+ } \
+ NSSRWLock_LockWrite(cache->lock); \
+}
+
+#define DPCache_UnlockWrite() { \
+ if (readlocked){ \
+ NSSRWLock_LockRead(cache->lock); \
+ } \
+ NSSRWLock_UnlockWrite(cache->lock); \
+}
+
+#else
+
+#define DPCache_LockWrite() {}
+
+#define DPCache_UnlockWrite() {}
+
+#endif
+
+SECStatus DPCache_Update(CRLDPCache* cache, CERTCertificate* issuer,
+ void* wincx, PRBool readlocked)
+{
+ /* Update the CRLDPCache now. We don't cache token CRL lookup misses
+ yet, as we have no way of getting notified of new PKCS#11 object
+ creation that happens in a token */
+ SECStatus rv = SECSuccess;
+ PRUint32 i = 0;
+ PRBool updated = PR_FALSE;
+
+ if (!cache) {
+ return SECFailure;
+ }
+
+ /* verify CRLs that couldn't be checked when inserted into the cache
+ because the issuer cert was unavailable. These are CRLs that were
+ inserted into the cache through SEC_FindCrlByName, rather than
+ through a certificate verification (CERT_CheckCRL) */
+ if (issuer) {
+ /* if we didn't have a valid issuer cert yet, but we do now. add it */
+ if (NULL == cache->issuer) {
+ /* save the issuer cert */
+ cache->issuer = CERT_DupCertificate(issuer);
+ }
+
+ /* re-process all unverified CRLs */
+ if (cache->issuer) {
+ for (i = 0; i < cache->ncrls ; i++) {
+ CERTSignedCrl* acrl = cache->crls[i];
+ if (PR_TRUE == GetOpaqueCRLFields(acrl)->unverified) {
+ DPCache_LockWrite();
+ /* check that we are the first thread to update */
+ if (PR_TRUE == GetOpaqueCRLFields(acrl)->unverified) {
+ DPCache_Refresh(cache, acrl, wincx);
+ /* also check all the other CRLs */
+ for (i = i+1 ; i < cache->ncrls ; i++) {
+ acrl = cache->crls[i];
+ if (acrl && (PR_TRUE == GetOpaqueCRLFields(acrl)->unverified)) {
+ DPCache_Refresh(cache, acrl, wincx);
+ }
+ }
+ }
+ DPCache_UnlockWrite();
+ break;
+ }
+ }
+ }
+ }
+
+ if (cache->ncrls) {
+ /* check if all CRLs still exist */
+ for (i = 0; (i < cache->ncrls) && (PR_FALSE == updated); i++)
+ {
+ CERTSignedCrl* savcrl = cache->crls[i];
+ if (savcrl && (PR_TRUE != CRLStillExists(savcrl))) {
+
+ /* this CRL is gone */
+ DPCache_LockWrite();
+ /* first, we need to check if another thread updated
+ it before we did, and abort if it has been modified since
+ we acquired the lock */
+ if ((savcrl == cache->crls[i]) &&
+ PR_TRUE != CRLStillExists(savcrl)) {
+ /* the CRL is gone. And we are the one to do the update */
+ /* Mark the CRL deleted */
+ GetOpaqueCRLFields(savcrl)->deleted = PR_TRUE;
+ /* also check all the other CRLs */
+ for (i = i+1 ; i < cache->ncrls ; i++) {
+ CERTSignedCrl* acrl = cache->crls[i];
+ if (acrl && (PR_TRUE != CRLStillExists(acrl))) {
+ GetOpaqueCRLFields(acrl)->deleted = PR_TRUE;
+ }
+ }
+ /* and try to fetch a new one */
+ rv = DPCache_Fetch(cache, wincx);
+ updated = PR_TRUE;
+ if (SECSuccess == rv) {
+ rv = DPCache_Cleanup(cache); /* clean up deleted CRLs
+ from the cache*/
+ }
+ }
+ DPCache_UnlockWrite();
+ }
+ }
+ } else {
+ /* we had zero CRL for this DP, try to get one from tokens */
+ DPCache_LockWrite();
+ /* check if another thread updated before us, and skip update if so */
+ if (0 == cache->ncrls)
+ {
+ /* we are the first */
+ rv = DPCache_Fetch(cache, wincx);
+ }
+ DPCache_UnlockWrite();
+ }
+
+ return rv;
+}
+
+SECStatus DPCache_Initialize(CRLDPCache* cache, CERTCertificate* issuer,
+ SECItem* subject, SECItem* dp)
+{
+ PORT_Assert(cache);
+ if (!cache) {
+ return SECFailure;
+ }
+ memset(cache, 0, sizeof(CRLDPCache));
+#ifdef USE_RWLOCK
+ cache->lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
+#else
+ cache->lock = PR_NewLock();
+#endif
+ if (!cache->lock)
+ {
+ return SECFailure;
+ }
+ if (issuer)
+ {
+ cache->issuer = CERT_DupCertificate(issuer);
+ }
+ cache->distributionPoint = SECITEM_DupItem(dp);
+ cache->subject = SECITEM_DupItem(subject);
+ return SECSuccess;
+}
+
+SECStatus IssuerCache_Create(CRLIssuerCache** returned,
+ CERTCertificate* issuer,
+ SECItem* subject, SECItem* dp)
+{
+ SECStatus rv = SECSuccess;
+ CRLIssuerCache* cache = NULL;
+ PORT_Assert(returned);
+ PORT_Assert(subject);
+ if (!returned || !subject)
+ {
+ return SECFailure;
+ }
+ cache = (CRLIssuerCache*) PR_Malloc(sizeof(CRLIssuerCache));
+ if (!cache)
+ {
+ return SECFailure;
+ }
+ memset(cache, 0, sizeof(CRLIssuerCache));
+ cache->subject = SECITEM_DupItem(subject);
+#if 0
+ /* XCRL */
+ cache->lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
+ if (!cache->lock)
+ {
+ rv = SECFailure;
+ }
+ if (SECSuccess == rv && issuer)
+ {
+ cache->issuer = CERT_DupCertificate(issuer);
+ if (!cache->issuer)
+ {
+ rv = SECFailure;
+ }
+ }
+#endif
+ if (SECSuccess != rv)
+ {
+ return IssuerCache_Destroy(cache);
+ }
+ *returned = cache;
+ return SECSuccess;
+}
+
+SECStatus IssuerCache_AddDP(CRLIssuerCache* cache, CERTCertificate* issuer,
+ SECItem* subject, SECItem* dp, CRLDPCache** newdpc)
+{
+ SECStatus rv = SECSuccess;
+ /* now create the required DP cache object */
+ if (!dp) {
+ /* default distribution point */
+ rv = DPCache_Initialize(&cache->dp, issuer, subject, NULL);
+ if (SECSuccess == rv) {
+ cache->dpp = &cache->dp;
+ if (newdpc) {
+ *newdpc = cache->dpp;
+ }
+ }
+ } else {
+ /* we should never hit this until we support multiple DPs */
+ PORT_Assert(dp);
+ rv = SECFailure;
+ /* XCRL allocate a new distribution point cache object, initialize it,
+ and add it to the hash table of DPs */
+ }
+ return rv;
+}
+
+SECStatus CRLCache_AddIssuer(CRLIssuerCache* issuer)
+{
+ PORT_Assert(issuer);
+ PORT_Assert(crlcache.issuers);
+ if (!issuer || !crlcache.issuers) {
+ return SECFailure;
+ }
+ if (NULL == PL_HashTableAdd(crlcache.issuers, (void*) issuer->subject,
+ (void*) issuer)) {
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+SECStatus GetIssuerCache(CRLCache* cache, SECItem* subject, CRLIssuerCache** returned)
+{
+ /* we need to look up the issuer in the hash table */
+ SECStatus rv = SECSuccess;
+ PORT_Assert(cache);
+ PORT_Assert(subject);
+ PORT_Assert(returned);
+ PORT_Assert(crlcache.issuers);
+ if (!cache || !subject || !returned || !crlcache.issuers) {
+ rv = SECFailure;
+ }
+
+ if (SECSuccess == rv){
+ *returned = (CRLIssuerCache*) PL_HashTableLookup(crlcache.issuers,
+ (void*) subject);
+ }
+
+ return rv;
+}
+
+CERTSignedCrl* GetBestCRL(CRLDPCache* cache)
+{
+ PRUint32 i = 0;
+ PR_ASSERT(cache);
+ if (!cache) {
+ return NULL;
+ }
+ if (0 == cache->ncrls) {
+ /* no CRLs in the cache */
+ return NULL;
+ }
+ /* first, check if we have a valid full CRL, and use that */
+ if (cache->full) {
+ return SEC_DupCrl(cache->full);
+ }
+ /* otherwise, check all the fetched CRLs for one with valid DER */
+ for (i = 0; i < cache->ncrls ; i++) {
+ CERTSignedCrl* acrl = cache->crls[i];
+ if (PR_FALSE == GetOpaqueCRLFields(acrl)->bad) {
+ SECStatus rv = CERT_CompleteCRLDecodeEntries(acrl);
+ if (SECSuccess == rv) {
+ return SEC_DupCrl(acrl);
+ }
+ }
+ }
+ return NULL;
+}
+
+CRLDPCache* GetDPCache(CRLIssuerCache* cache, SECItem* dp)
+{
+ CRLDPCache* dpp = NULL;
+ PORT_Assert(cache);
+ /* XCRL for now we only support the "default" DP, ie. the
+ full CRL. So we can return the global one without locking. In
+ the future we will have a lock */
+ PORT_Assert(NULL == dp);
+ if (!cache || dp) {
+ return NULL;
+ }
+#if 0
+ /* XCRL */
+ NSSRWLock_LockRead(cache->lock);
+#endif
+ dpp = cache->dpp;
+#if 0
+ /* XCRL */
+ NSSRWLock_UnlockRead(cache->lock);
+#endif
+ return dpp;
+}
+
+SECStatus AcquireDPCache(CERTCertificate* issuer, SECItem* subject, SECItem* dp,
+ int64 t, void* wincx, CRLDPCache** dpcache,
+ PRBool* writeLocked)
+{
+ SECStatus rv = SECSuccess;
+ CRLIssuerCache* issuercache = NULL;
+
+ PORT_Assert(crlcache.lock);
+ if (!crlcache.lock) {
+ /* CRL cache is not initialized */
+ return SECFailure;
+ }
+ PR_Lock(crlcache.lock);
+ rv = GetIssuerCache(&crlcache, subject, &issuercache);
+ if (SECSuccess != rv) {
+ PR_Unlock(crlcache.lock);
+ return SECFailure;
+ }
+ if (!issuercache) {
+ /* there is no cache for this issuer yet. This means this is the
+ first time we look up a cert from that issuer, and we need to
+ create the cache. Do it within the global cache lock to ensure
+ no two threads will simultaneously try to create the same issuer
+ cache. XXX this could be optimized with a r/w lock at this level
+ too. But the code would have to check if it already exists when
+ adding to the hash table */
+
+ rv = IssuerCache_Create(&issuercache, issuer, subject, dp);
+ if (SECSuccess == rv && !issuercache) {
+ PORT_Assert(issuercache);
+ rv = SECFailure;
+ }
+
+ if (SECSuccess == rv) {
+ /* This is the first time we look up a cert of this issuer.
+ Create the DPCache for this DP . */
+ rv = IssuerCache_AddDP(issuercache, issuer, subject, dp, dpcache);
+ }
+
+ if (SECSuccess == rv) {
+ /* lock the DPCache for write to ensure the update happens in this thread */
+ *writeLocked = PR_TRUE;
+#ifdef USE_RWLOCK
+ NSSRWLock_LockWrite((*dpcache)->lock);
+#else
+ PR_Lock((*dpcache)->lock);
+#endif
+ }
+
+ if (SECSuccess == rv) {
+ /* now add the new issuer cache to the global hash table of issuers */
+ rv = CRLCache_AddIssuer(issuercache);
+ if (SECSuccess != rv) {
+ /* failure */
+ rv = SECFailure;
+ }
+ }
+
+ /* now unlock the global cache. We only want to lock the hash table
+ addition. Holding it longer would hurt scalability */
+ PR_Unlock(crlcache.lock);
+
+ if (SECSuccess != rv && issuercache) {
+ if (PR_TRUE == *writeLocked) {
+#ifdef USE_RWLOCK
+ NSSRWLock_UnlockWrite((*dpcache)->lock);
+#else
+ PR_Unlock((*dpcache)->lock);
+#endif
+ }
+ IssuerCache_Destroy(issuercache);
+ issuercache = NULL;
+ }
+
+ if (SECSuccess != rv) {
+ return SECFailure;
+ }
+ } else {
+ PR_Unlock(crlcache.lock);
+ *dpcache = GetDPCache(issuercache, dp);
+ }
+ /* we now have a DPCache that we can use for lookups */
+ /* lock it for read, unless we already locked for write */
+ if (PR_FALSE == *writeLocked)
+ {
+#ifdef USE_RWLOCK
+ NSSRWLock_LockRead((*dpcache)->lock);
+#else
+ PR_Lock((*dpcache)->lock);
+#endif
+ }
+
+ if (SECSuccess == rv) {
+ /* currently there is always one and only one DPCache */
+ PORT_Assert(*dpcache);
+ if (*dpcache)
+ {
+ /* make sure the DP cache is up to date before using it */
+ rv = DPCache_Update(*dpcache, issuer, wincx, PR_FALSE == *writeLocked);
+ }
+ else
+ {
+ rv = SECFailure;
+ }
+ }
+ return rv;
+}
+
+void ReleaseDPCache(CRLDPCache* dpcache, PRBool writeLocked)
+{
+ if (!dpcache) {
+ return;
+ }
+ if (PR_TRUE == writeLocked) {
+#ifdef USE_RWLOCK
+ NSSRWLock_UnlockWrite(dpcache->lock);
+#else
+ PR_Unlock(dpcache->lock);
+#endif
+ } else {
+#ifdef USE_RWLOCK
+ NSSRWLock_UnlockRead(dpcache->lock);
+#else
+ PR_Unlock(dpcache->lock);
+#endif
+ }
+}
+
+SECStatus
+CERT_CheckCRL(CERTCertificate* cert, CERTCertificate* issuer, SECItem* dp,
+ int64 t, void* wincx)
+{
+ PRBool lockedwrite = PR_FALSE;
+ SECStatus rv = SECSuccess;
+ CRLDPCache* dpcache = NULL;
+ if (!cert || !issuer) {
+ return SECFailure;
+ }
+
+ rv = AcquireDPCache(issuer, &issuer->derSubject, dp, t, wincx, &dpcache, &lockedwrite);
+
+ if (SECSuccess == rv) {
+ /* now look up the certificate SN in the DP cache's CRL */
+ CERTCrlEntry* entry = NULL;
+ rv = DPCache_Lookup(dpcache, &cert->serialNumber, &entry);
+ if (SECSuccess == rv && entry) {
+ /* check the time if we have one */
+ if (entry->revocationDate.data && entry->revocationDate.len) {
+ int64 revocationDate = 0;
+ if (SECSuccess == DER_UTCTimeToTime(&revocationDate,
+ &entry->revocationDate)) {
+ /* we got a good revocation date, only consider the
+ certificate revoked if the time we are inquiring about
+ is past the revocation date */
+ if (t>=revocationDate) {
+ rv = SECFailure;
+ }
+ } else {
+ /* invalid revocation date, consider the certificate
+ permanently revoked */
+ rv = SECFailure;
+ }
+ } else {
+ /* no revocation date, certificate is permanently revoked */
+ rv = SECFailure;
+ }
+ if (SECFailure == rv) {
+ PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
+ }
+ }
+ }
+
+ ReleaseDPCache(dpcache, lockedwrite);
+ return rv;
+}
+
+CERTSignedCrl *
+SEC_FindCrlByName(CERTCertDBHandle *handle, SECItem *crlKey, int type)
+{
+ CERTSignedCrl* acrl = NULL;
+ CRLDPCache* dpcache = NULL;
+ SECStatus rv = SECSuccess;
+ PRBool writeLocked = PR_FALSE;
+
+ rv = AcquireDPCache(NULL, crlKey, NULL, 0, NULL, &dpcache, &writeLocked);
+ if (SECSuccess == rv)
+ {
+ acrl = GetBestCRL(dpcache);
+ ReleaseDPCache(dpcache, writeLocked);
+ }
+ return acrl;
+}
+
+void CERT_CRLCacheRefreshIssuer(CERTCertDBHandle* dbhandle, SECItem* crlKey)
+{
+ CERTSignedCrl* acrl = NULL;
+ CRLDPCache* cache = NULL;
+ SECStatus rv = SECSuccess;
+ PRBool writeLocked = PR_FALSE;
+
+ (void) dbhandle; /* silence compiler warnings */
+
+ rv = AcquireDPCache(NULL, crlKey, NULL, 0, NULL, &cache, &writeLocked);
+ if (SECSuccess != rv)
+ {
+ return;
+ }
+ if (PR_TRUE == writeLocked)
+ {
+ /* the DPCache is write-locked. This means that the issuer was just
+ added to the CRL cache. There is no need to do anything */
+ }
+ else
+ {
+ PRBool readlocked = PR_TRUE;
+ /* we need to invalidate the DPCache here */
+ DPCache_LockWrite();
+ DPCache_Empty(cache);
+ DPCache_Cleanup(cache);
+ DPCache_UnlockWrite();
+ }
+ ReleaseDPCache(cache, writeLocked);
+ return;
+}
+
diff --git a/security/nss/lib/certdb/genname.c b/security/nss/lib/certdb/genname.c
new file mode 100644
index 000000000..a8dcf6dff
--- /dev/null
+++ b/security/nss/lib/certdb/genname.c
@@ -0,0 +1,1610 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+#include "plarena.h"
+#include "seccomon.h"
+#include "secitem.h"
+#include "secoidt.h"
+#include "mcom_db.h"
+#include "secasn1.h"
+#include "secder.h"
+#include "certt.h"
+#include "cert.h"
+#include "xconst.h"
+#include "secerr.h"
+#include "secoid.h"
+#include "prprf.h"
+#include "genname.h"
+
+
+
+static const SEC_ASN1Template CERTNameConstraintTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTNameConstraint) },
+ { SEC_ASN1_ANY, offsetof(CERTNameConstraint, DERName) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 0,
+ offsetof(CERTNameConstraint, min), SEC_IntegerTemplate },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 1,
+ offsetof(CERTNameConstraint, max), SEC_IntegerTemplate },
+ { 0, }
+};
+
+const SEC_ASN1Template CERT_NameConstraintSubtreeSubTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_AnyTemplate }
+};
+
+
+const SEC_ASN1Template CERT_NameConstraintSubtreePermitedTemplate[] = {
+ { SEC_ASN1_CONTEXT_SPECIFIC | 0, 0, CERT_NameConstraintSubtreeSubTemplate }
+};
+
+const SEC_ASN1Template CERT_NameConstraintSubtreeExcludedTemplate[] = {
+ { SEC_ASN1_CONTEXT_SPECIFIC | 1, 0, CERT_NameConstraintSubtreeSubTemplate }
+};
+
+
+static const SEC_ASN1Template CERTNameConstraintsTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTNameConstraints) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 0,
+ offsetof(CERTNameConstraints, DERPermited), CERT_NameConstraintSubtreeSubTemplate},
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 1,
+ offsetof(CERTNameConstraints, DERExcluded), CERT_NameConstraintSubtreeSubTemplate},
+ { 0, }
+};
+
+
+static const SEC_ASN1Template CERTOthNameTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(OtherName) },
+ { SEC_ASN1_OBJECT_ID,
+ offsetof(OtherName, oid) },
+ { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 0,
+ offsetof(OtherName, name), SEC_AnyTemplate },
+ { 0, }
+};
+
+static const SEC_ASN1Template CERTOtherNameTemplate[] = {
+ { SEC_ASN1_CONTEXT_SPECIFIC | 0 ,
+ offsetof(CERTGeneralName, name.OthName), CERTOthNameTemplate,
+ sizeof(CERTGeneralName) }
+};
+
+static const SEC_ASN1Template CERTOtherName2Template[] = {
+ { SEC_ASN1_SEQUENCE | SEC_ASN1_CONTEXT_SPECIFIC | 0 ,
+ 0, NULL, sizeof(CERTGeneralName) },
+ { SEC_ASN1_OBJECT_ID,
+ offsetof(CERTGeneralName, name.OthName) + offsetof(OtherName, oid) },
+ { SEC_ASN1_ANY,
+ offsetof(CERTGeneralName, name.OthName) + offsetof(OtherName, name) },
+ { 0, }
+};
+
+static const SEC_ASN1Template CERT_RFC822NameTemplate[] = {
+ { SEC_ASN1_CONTEXT_SPECIFIC | 1 ,
+ offsetof(CERTGeneralName, name.other), SEC_IA5StringTemplate,
+ sizeof (CERTGeneralName)}
+};
+
+static const SEC_ASN1Template CERT_DNSNameTemplate[] = {
+ { SEC_ASN1_CONTEXT_SPECIFIC | 2 ,
+ offsetof(CERTGeneralName, name.other), SEC_IA5StringTemplate,
+ sizeof (CERTGeneralName)}
+};
+
+static const SEC_ASN1Template CERT_X400AddressTemplate[] = {
+ { SEC_ASN1_ANY | SEC_ASN1_CONTEXT_SPECIFIC | 3,
+ offsetof(CERTGeneralName, name.other), SEC_AnyTemplate,
+ sizeof (CERTGeneralName)}
+};
+
+static const SEC_ASN1Template CERT_DirectoryNameTemplate[] = {
+ { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 4,
+ offsetof(CERTGeneralName, derDirectoryName), SEC_AnyTemplate,
+ sizeof (CERTGeneralName)}
+};
+
+
+static const SEC_ASN1Template CERT_EDIPartyNameTemplate[] = {
+ { SEC_ASN1_ANY | SEC_ASN1_CONTEXT_SPECIFIC | 5,
+ offsetof(CERTGeneralName, name.other), SEC_AnyTemplate,
+ sizeof (CERTGeneralName)}
+};
+
+static const SEC_ASN1Template CERT_URITemplate[] = {
+ { SEC_ASN1_CONTEXT_SPECIFIC | 6 ,
+ offsetof(CERTGeneralName, name.other), SEC_IA5StringTemplate,
+ sizeof (CERTGeneralName)}
+};
+
+static const SEC_ASN1Template CERT_IPAddressTemplate[] = {
+ { SEC_ASN1_CONTEXT_SPECIFIC | 7 ,
+ offsetof(CERTGeneralName, name.other), SEC_OctetStringTemplate,
+ sizeof (CERTGeneralName)}
+};
+
+static const SEC_ASN1Template CERT_RegisteredIDTemplate[] = {
+ { SEC_ASN1_CONTEXT_SPECIFIC | 8 ,
+ offsetof(CERTGeneralName, name.other), SEC_ObjectIDTemplate,
+ sizeof (CERTGeneralName)}
+};
+
+
+const SEC_ASN1Template CERT_GeneralNamesTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_AnyTemplate }
+};
+
+
+
+void
+CERT_DestroyGeneralNameList(CERTGeneralNameList *list)
+{
+ PZLock *lock;
+
+ if (list != NULL) {
+ lock = list->lock;
+ PZ_Lock(lock);
+ if (--list->refCount <= 0 && list->arena != NULL) {
+ PORT_FreeArena(list->arena, PR_FALSE);
+ PZ_Unlock(lock);
+ PZ_DestroyLock(lock);
+ } else {
+ PZ_Unlock(lock);
+ }
+ }
+ return;
+}
+
+CERTGeneralNameList *
+CERT_CreateGeneralNameList(CERTGeneralName *name) {
+ PRArenaPool *arena;
+ CERTGeneralNameList *list = NULL;
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ goto done;
+ }
+ list = (CERTGeneralNameList *)
+ PORT_ArenaZAlloc(arena, sizeof(CERTGeneralNameList));
+ if (name != NULL) {
+ list->name = (CERTGeneralName *)
+ PORT_ArenaZAlloc(arena, sizeof(CERTGeneralName));
+ list->name->l.next = list->name->l.prev = &list->name->l;
+ CERT_CopyGeneralName(arena, list->name, name);
+ }
+ list->lock = PZ_NewLock(nssILockList);
+ list->arena = arena;
+ list->refCount = 1;
+done:
+ return list;
+}
+
+CERTGeneralName *
+cert_get_next_general_name(CERTGeneralName *current)
+{
+ PRCList *next;
+
+ next = current->l.next;
+ return (CERTGeneralName *) (((char *) next) - offsetof(CERTGeneralName, l));
+}
+
+CERTGeneralName *
+cert_get_prev_general_name(CERTGeneralName *current)
+{
+ PRCList *prev;
+ prev = current->l.prev;
+ return (CERTGeneralName *) (((char *) prev) - offsetof(CERTGeneralName, l));
+}
+
+CERTNameConstraint *
+cert_get_next_name_constraint(CERTNameConstraint *current)
+{
+ PRCList *next;
+
+ next = current->l.next;
+ return (CERTNameConstraint *) (((char *) next) - offsetof(CERTNameConstraint, l));
+}
+
+CERTNameConstraint *
+cert_get_prev_name_constraint(CERTNameConstraint *current)
+{
+ PRCList *prev;
+ prev = current->l.prev;
+ return (CERTNameConstraint *) (((char *) prev) - offsetof(CERTNameConstraint, l));
+}
+
+SECItem *
+CERT_EncodeGeneralName(CERTGeneralName *genName, SECItem *dest, PRArenaPool *arena)
+{
+
+
+ PORT_Assert(arena);
+ if (arena == NULL) {
+ goto loser;
+ }
+ if (dest == NULL) {
+ dest = (SECItem *) PORT_ArenaZAlloc(arena, sizeof(SECItem));
+ }
+ switch (genName->type) {
+ case certURI:
+ dest = SEC_ASN1EncodeItem(arena, dest, genName,
+ CERT_URITemplate);
+ break;
+ case certRFC822Name:
+ dest = SEC_ASN1EncodeItem(arena, dest, genName,
+ CERT_RFC822NameTemplate);
+ break;
+ case certDNSName:
+ dest = SEC_ASN1EncodeItem(arena, dest, genName,
+ CERT_DNSNameTemplate);
+ break;
+ case certIPAddress:
+ dest = SEC_ASN1EncodeItem(arena, dest, genName,
+ CERT_IPAddressTemplate);
+ break;
+ case certOtherName:
+ dest = SEC_ASN1EncodeItem(arena, dest, genName,
+ CERTOtherNameTemplate);
+ break;
+ case certRegisterID:
+ dest = SEC_ASN1EncodeItem(arena, dest, genName,
+ CERT_RegisteredIDTemplate);
+ break;
+ case certEDIPartyName:
+ /* for this type, we expect the value is already encoded */
+ dest = SEC_ASN1EncodeItem (arena, dest, genName,
+ CERT_EDIPartyNameTemplate);
+ break;
+ case certX400Address:
+ /* for this type, we expect the value is already encoded */
+ dest = SEC_ASN1EncodeItem (arena, dest, genName,
+ CERT_X400AddressTemplate);
+ break;
+ case certDirectoryName:
+ if (genName->derDirectoryName.data == NULL) {
+ /* The field hasn't been encoded yet. */
+ SEC_ASN1EncodeItem (arena, &(genName->derDirectoryName),
+ &(genName->name.directoryName),
+ CERT_NameTemplate);
+ }
+ if (genName->derDirectoryName.data == NULL) {
+ goto loser;
+ }
+ dest = SEC_ASN1EncodeItem(arena, dest, genName,
+ CERT_DirectoryNameTemplate);
+ break;
+ }
+ if (!dest) {
+ goto loser;
+ }
+ return dest;
+loser:
+ return NULL;
+}
+
+
+
+SECItem **
+cert_EncodeGeneralNames(PRArenaPool *arena, CERTGeneralName *names)
+{
+ CERTGeneralName *current_name;
+ SECItem **items = NULL;
+ int count = 0;
+ int i;
+ PRCList *head;
+
+ PORT_Assert(arena);
+ current_name = names;
+ if (names != NULL) {
+ count = 1;
+ }
+ head = &(names->l);
+ while (current_name->l.next != head) {
+ current_name = cert_get_next_general_name(current_name);
+ ++count;
+ }
+ current_name = cert_get_next_general_name(current_name);
+ items = (SECItem **) PORT_ArenaAlloc(arena, sizeof(SECItem *) * (count + 1));
+
+ if (items == NULL) {
+ goto loser;
+ }
+ for (i = 0; i < count; i++) {
+ items[i] = CERT_EncodeGeneralName(current_name, (SECItem *) NULL, arena);
+ if (items[i] == NULL) {
+ goto loser;
+ }
+ current_name = cert_get_next_general_name(current_name);
+ }
+ items[i] = NULL;
+ return items;
+loser:
+ return NULL;
+}
+
+CERTGeneralName *
+CERT_DecodeGeneralName(PRArenaPool *arena,
+ SECItem *encodedName,
+ CERTGeneralName *genName)
+{
+ CERTGeneralNameType genNameType;
+ SECStatus rv = SECSuccess;
+
+ PORT_Assert(arena);
+ if (genName == NULL) {
+ genName = (CERTGeneralName *) PORT_ArenaZAlloc(arena, sizeof(CERTGeneralName));
+ }
+ genNameType = (CERTGeneralNameType)((*(encodedName->data) & 0x0f) + 1);
+ switch (genNameType) {
+ case certURI:
+ rv = SEC_ASN1DecodeItem(arena, genName, CERT_URITemplate, encodedName);
+ break;
+ case certRFC822Name:
+ rv = SEC_ASN1DecodeItem(arena, genName, CERT_RFC822NameTemplate, encodedName);
+ break;
+ case certDNSName:
+ rv = SEC_ASN1DecodeItem(arena, genName, CERT_DNSNameTemplate, encodedName);
+ break;
+ case certIPAddress:
+ rv = SEC_ASN1DecodeItem(arena, genName, CERT_IPAddressTemplate, encodedName);
+ break;
+ case certOtherName:
+ rv = SEC_ASN1DecodeItem(arena, genName, CERTOtherNameTemplate, encodedName);
+ break;
+ case certRegisterID:
+ rv = SEC_ASN1DecodeItem(arena, genName, CERT_RegisteredIDTemplate, encodedName);
+ break;
+ case certEDIPartyName:
+ rv = SEC_ASN1DecodeItem(arena, genName, CERT_EDIPartyNameTemplate, encodedName);
+ break;
+ case certX400Address:
+ rv = SEC_ASN1DecodeItem(arena, genName, CERT_X400AddressTemplate, encodedName);
+ break;
+ case certDirectoryName:
+ rv = SEC_ASN1DecodeItem
+ (arena, genName, CERT_DirectoryNameTemplate, encodedName);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = SEC_ASN1DecodeItem
+ (arena, &(genName->name.directoryName), CERT_NameTemplate,
+ &(genName->derDirectoryName));
+ break;
+ }
+
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ genName->type = genNameType;
+ genName->l.next = (PRCList *) ((char *) genName) + offsetof(CERTGeneralName, l);
+ genName->l.prev = genName->l.next;
+ return genName;
+loser:
+ return NULL;
+}
+
+CERTGeneralName *
+cert_DecodeGeneralNames (PRArenaPool *arena,
+ SECItem **encodedGenName)
+{
+ PRCList *head = NULL;
+ PRCList *tail = NULL;
+ CERTGeneralName *currentName = NULL;
+
+ PORT_Assert(arena);
+ if (!encodedGenName) {
+ goto loser;
+ }
+ while (*encodedGenName != NULL) {
+ currentName = CERT_DecodeGeneralName(arena, *encodedGenName, NULL);
+ if (currentName == NULL) {
+ goto loser;
+ }
+ if (head == NULL) {
+ head = &(currentName->l);
+ tail = head;
+ }
+ currentName->l.next = head;
+ currentName->l.prev = tail;
+ tail = &(currentName->l);
+ (cert_get_prev_general_name(currentName))->l.next = tail;
+ encodedGenName++;
+ }
+ (cert_get_next_general_name(currentName))->l.prev = tail;
+ return cert_get_next_general_name(currentName);
+loser:
+ return NULL;
+}
+
+void
+CERT_DestroyGeneralName(CERTGeneralName *name)
+{
+ cert_DestroyGeneralNames(name);
+}
+
+SECStatus
+cert_DestroyGeneralNames(CERTGeneralName *name)
+{
+ CERTGeneralName *first;
+ CERTGeneralName *next = NULL;
+
+
+ first = name;
+ do {
+ next = cert_get_next_general_name(name);
+ PORT_Free(name);
+ name = next;
+ } while (name != first);
+ return SECSuccess;
+}
+
+SECItem *
+cert_EncodeNameConstraint(CERTNameConstraint *constraint,
+ SECItem *dest,
+ PRArenaPool *arena)
+{
+ PORT_Assert(arena);
+ if (dest == NULL) {
+ dest = (SECItem *) PORT_ArenaZAlloc(arena, sizeof(SECItem));
+ if (dest == NULL) {
+ return NULL;
+ }
+ }
+ CERT_EncodeGeneralName(&(constraint->name), &(constraint->DERName),
+ arena);
+
+ dest = SEC_ASN1EncodeItem (arena, dest, constraint,
+ CERTNameConstraintTemplate);
+ return dest;
+}
+
+SECStatus
+cert_EncodeNameConstraintSubTree(CERTNameConstraint *constraints,
+ PRArenaPool *arena,
+ SECItem ***dest,
+ PRBool permited)
+{
+ CERTNameConstraint *current_constraint = constraints;
+ SECItem **items = NULL;
+ int count = 0;
+ int i;
+ PRCList *head;
+
+ PORT_Assert(arena);
+ if (constraints != NULL) {
+ count = 1;
+ }
+ head = (PRCList *) (((char *) constraints) + offsetof(CERTNameConstraint, l));
+ while (current_constraint->l.next != head) {
+ current_constraint = cert_get_next_name_constraint(current_constraint);
+ ++count;
+ }
+ current_constraint = cert_get_next_name_constraint(current_constraint);
+ items = (SECItem **) PORT_ArenaZAlloc(arena, sizeof(SECItem *) * (count + 1));
+
+ if (items == NULL) {
+ goto loser;
+ }
+ for (i = 0; i < count; i++) {
+ items[i] = cert_EncodeNameConstraint(current_constraint,
+ (SECItem *) NULL, arena);
+ if (items[i] == NULL) {
+ goto loser;
+ }
+ current_constraint = cert_get_next_name_constraint(current_constraint);
+ }
+ *dest = items;
+ if (*dest == NULL) {
+ goto loser;
+ }
+ return SECSuccess;
+loser:
+ return SECFailure;
+}
+
+SECStatus
+cert_EncodeNameConstraints(CERTNameConstraints *constraints,
+ PRArenaPool *arena,
+ SECItem *dest)
+{
+ SECStatus rv = SECSuccess;
+
+ PORT_Assert(arena);
+ if (constraints->permited != NULL) {
+ rv = cert_EncodeNameConstraintSubTree(constraints->permited, arena,
+ &constraints->DERPermited, PR_TRUE);
+ if (rv == SECFailure) {
+ goto loser;
+ }
+ }
+ if (constraints->excluded != NULL) {
+ rv = cert_EncodeNameConstraintSubTree(constraints->excluded, arena,
+ &constraints->DERExcluded, PR_FALSE);
+ if (rv == SECFailure) {
+ goto loser;
+ }
+ }
+ dest = SEC_ASN1EncodeItem(arena, dest, constraints,
+ CERTNameConstraintsTemplate);
+ if (dest == NULL) {
+ goto loser;
+ }
+ return SECSuccess;
+loser:
+ return SECFailure;
+}
+
+
+CERTNameConstraint *
+cert_DecodeNameConstraint(PRArenaPool *arena,
+ SECItem *encodedConstraint)
+{
+ CERTNameConstraint *constraint;
+ SECStatus rv = SECSuccess;
+ CERTGeneralName *temp;
+
+
+
+ PORT_Assert(arena);
+ constraint = (CERTNameConstraint *) PORT_ArenaZAlloc(arena, sizeof(CERTNameConstraint));
+ rv = SEC_ASN1DecodeItem(arena, constraint, CERTNameConstraintTemplate, encodedConstraint);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ temp = CERT_DecodeGeneralName(arena, &(constraint->DERName), &(constraint->name));
+ if (temp != &(constraint->name)) {
+ goto loser;
+ }
+
+ /* ### sjlee: since the name constraint contains only one
+ * CERTGeneralName, the list within CERTGeneralName shouldn't
+ * point anywhere else. Otherwise, bad things will happen.
+ */
+ constraint->name.l.prev = constraint->name.l.next = &(constraint->name.l);
+ return constraint;
+loser:
+ return NULL;
+}
+
+
+CERTNameConstraint *
+cert_DecodeNameConstraintSubTree(PRArenaPool *arena,
+ SECItem **subTree,
+ PRBool permited)
+{
+ CERTNameConstraint *current = NULL;
+ CERTNameConstraint *first = NULL;
+ CERTNameConstraint *last = NULL;
+ CERTNameConstraint *next = NULL;
+ int i = 0;
+
+ while (subTree[i] != NULL) {
+ current = cert_DecodeNameConstraint(arena, subTree[i]);
+ if (current == NULL) {
+ goto loser;
+ }
+ if (last == NULL) {
+ first = last = current;
+ }
+ current->l.prev = &(last->l);
+ current->l.next = last->l.next;
+ last->l.next = &(current->l);
+ i++;
+ }
+ first->l.prev = &(current->l);
+ return first;
+loser:
+ if (first) {
+ current = first;
+ do {
+ next = cert_get_next_name_constraint(current);
+ PORT_Free(current);
+ current = next;
+ }while (current != first);
+ }
+ return NULL;
+}
+
+CERTNameConstraints *
+cert_DecodeNameConstraints(PRArenaPool *arena,
+ SECItem *encodedConstraints)
+{
+ CERTNameConstraints *constraints;
+ SECStatus rv;
+
+ PORT_Assert(arena);
+ PORT_Assert(encodedConstraints);
+ constraints = (CERTNameConstraints *) PORT_ArenaZAlloc(arena,
+ sizeof(CERTNameConstraints));
+ if (constraints == NULL) {
+ goto loser;
+ }
+ rv = SEC_ASN1DecodeItem(arena, constraints, CERTNameConstraintsTemplate,
+ encodedConstraints);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ if (constraints->DERPermited != NULL && constraints->DERPermited[0] != NULL) {
+ constraints->permited = cert_DecodeNameConstraintSubTree(arena,
+ constraints->DERPermited,
+ PR_TRUE);
+ if (constraints->permited == NULL) {
+ goto loser;
+ }
+ }
+ if (constraints->DERExcluded != NULL && constraints->DERExcluded[0] != NULL) {
+ constraints->excluded = cert_DecodeNameConstraintSubTree(arena,
+ constraints->DERExcluded,
+ PR_FALSE);
+ if (constraints->excluded == NULL) {
+ goto loser;
+ }
+ }
+ return constraints;
+loser:
+ return NULL;
+}
+
+
+SECStatus
+CERT_CopyGeneralName(PRArenaPool *arena,
+ CERTGeneralName *dest,
+ CERTGeneralName *src)
+{
+ SECStatus rv;
+ CERTGeneralName *destHead = dest;
+ CERTGeneralName *srcHead = src;
+ CERTGeneralName *temp;
+
+ PORT_Assert(dest != NULL);
+ dest->type = src->type;
+ do {
+ switch (src->type) {
+ case certDirectoryName: {
+ rv = SECITEM_CopyItem(arena, &dest->derDirectoryName, &src->derDirectoryName);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ rv = CERT_CopyName(arena, &dest->name.directoryName, &src->name.directoryName);
+ break;
+ }
+ case certOtherName: {
+ rv = SECITEM_CopyItem(arena, &dest->name.OthName.name, &src->name.OthName.name);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ rv = SECITEM_CopyItem(arena, &dest->name.OthName.oid, &src->name.OthName.oid);
+ break;
+ }
+ default: {
+ rv = SECITEM_CopyItem(arena, &dest->name.other, &src->name.other);
+ }
+ }
+ src = cert_get_next_general_name(src);
+ /* if there is only one general name, we shouldn't do this */
+ if (src != srcHead) {
+ if (dest->l.next == &destHead->l) {
+ if (arena) {
+ temp = (CERTGeneralName *)
+ PORT_ArenaZAlloc(arena, sizeof(CERTGeneralName));
+ } else {
+ temp = (CERTGeneralName *)
+ PORT_ZAlloc(sizeof(CERTGeneralName));
+ }
+ temp->l.next = &destHead->l;
+ temp->l.prev = &dest->l;
+ destHead->l.prev = &temp->l;
+ dest->l.next = &temp->l;
+ dest = temp;
+ } else {
+ dest = cert_get_next_general_name(dest);
+ }
+ }
+ } while (src != srcHead && rv == SECSuccess);
+ return rv;
+}
+
+
+CERTGeneralNameList *
+CERT_DupGeneralNameList(CERTGeneralNameList *list)
+{
+ if (list != NULL) {
+ PZ_Lock(list->lock);
+ list->refCount++;
+ PZ_Unlock(list->lock);
+ }
+ return list;
+}
+
+CERTNameConstraint *
+CERT_CopyNameConstraint(PRArenaPool *arena,
+ CERTNameConstraint *dest,
+ CERTNameConstraint *src)
+{
+ SECStatus rv;
+
+ if (dest == NULL) {
+ dest = (CERTNameConstraint *) PORT_ArenaZAlloc(arena, sizeof(CERTNameConstraint));
+ /* mark that it is not linked */
+ dest->name.l.prev = dest->name.l.next = &(dest->name.l);
+ }
+ rv = CERT_CopyGeneralName(arena, &dest->name, &src->name);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = SECITEM_CopyItem(arena, &dest->DERName, &src->DERName);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = SECITEM_CopyItem(arena, &dest->min, &src->min);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = SECITEM_CopyItem(arena, &dest->max, &src->max);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ dest->l.prev = dest->l.next = &dest->l;
+ return dest;
+loser:
+ return NULL;
+}
+
+
+CERTGeneralName *
+cert_CombineNamesLists(CERTGeneralName *list1, CERTGeneralName *list2)
+{
+ PRCList *begin1;
+ PRCList *begin2;
+ PRCList *end1;
+ PRCList *end2;
+
+ if (list1 == NULL){
+ return list2;
+ } else if (list2 == NULL) {
+ return list1;
+ } else {
+ begin1 = &list1->l;
+ begin2 = &list2->l;
+ end1 = list1->l.prev;
+ end2 = list2->l.prev;
+ end1->next = begin2;
+ end2->next = begin1;
+ begin1->prev = end2;
+ begin2->prev = end1;
+ return list1;
+ }
+}
+
+
+CERTNameConstraint *
+cert_CombineConstraintsLists(CERTNameConstraint *list1, CERTNameConstraint *list2)
+{
+ PRCList *begin1;
+ PRCList *begin2;
+ PRCList *end1;
+ PRCList *end2;
+
+ if (list1 == NULL){
+ return list2;
+ } else if (list2 == NULL) {
+ return list1;
+ } else {
+ begin1 = &list1->l;
+ begin2 = &list2->l;
+ end1 = list1->l.prev;
+ end2 = list2->l.prev;
+ end1->next = begin2;
+ end2->next = begin1;
+ begin1->prev = end2;
+ begin2->prev = end1;
+ return list1;
+ }
+}
+
+
+CERTNameConstraint *
+CERT_AddNameConstraint(CERTNameConstraint *list,
+ CERTNameConstraint *constraint)
+{
+ PORT_Assert(constraint != NULL);
+ constraint->l.next = constraint->l.prev = &constraint->l;
+ list = cert_CombineConstraintsLists(list, constraint);
+ return list;
+}
+
+
+SECStatus
+CERT_GetNameConstriantByType (CERTNameConstraint *constraints,
+ CERTGeneralNameType type,
+ CERTNameConstraint **returnList,
+ PRArenaPool *arena)
+{
+ CERTNameConstraint *current;
+ CERTNameConstraint *temp;
+
+ *returnList = NULL;
+ if (!constraints)
+ return SECSuccess;
+ current = constraints;
+
+ do {
+ if (current->name.type == type ||
+ (type == certDirectoryName && current->name.type == certRFC822Name)) {
+ temp = NULL;
+ temp = CERT_CopyNameConstraint(arena, temp, current);
+ if (temp == NULL) {
+ goto loser;
+ }
+ *returnList = CERT_AddNameConstraint(*returnList, temp);
+ }
+ current = cert_get_next_name_constraint(current);
+ } while (current != constraints);
+ return SECSuccess;
+loser:
+ return SECFailure;
+}
+
+
+void *
+CERT_GetGeneralNameByType (CERTGeneralName *genNames,
+ CERTGeneralNameType type, PRBool derFormat)
+{
+ CERTGeneralName *current;
+
+ if (!genNames)
+ return (NULL);
+ current = genNames;
+
+ do {
+ if (current->type == type) {
+ switch (type) {
+ case certDNSName:
+ case certEDIPartyName:
+ case certIPAddress:
+ case certRegisterID:
+ case certRFC822Name:
+ case certX400Address:
+ case certURI: {
+ return &(current->name.other);
+ }
+ case certOtherName: {
+ return &(current->name.OthName);
+ break;
+ }
+ case certDirectoryName: {
+ if (derFormat) {
+ return &(current->derDirectoryName);
+ } else{
+ return &(current->name.directoryName);
+ }
+ break;
+ }
+ }
+ }
+ current = cert_get_next_general_name(current);
+ } while (current != genNames);
+ return (NULL);
+}
+
+int
+CERT_GetNamesLength(CERTGeneralName *names)
+{
+ int length = 0;
+ CERTGeneralName *first;
+
+ first = names;
+ if (names != NULL) {
+ do {
+ length++;
+ names = cert_get_next_general_name(names);
+ } while (names != first);
+ }
+ return length;
+}
+
+CERTGeneralName *
+CERT_GetCertificateNames(CERTCertificate *cert, PRArenaPool *arena)
+{
+ CERTGeneralName *DN;
+ CERTGeneralName *altName;
+ SECItem altNameExtension;
+ SECStatus rv;
+
+
+ DN = (CERTGeneralName *) PORT_ArenaZAlloc(arena, sizeof(CERTGeneralName));
+ if (DN == NULL) {
+ goto loser;
+ }
+ rv = CERT_CopyName(arena, &DN->name.directoryName, &cert->subject);
+ DN->type = certDirectoryName;
+ DN->l.next = DN->l.prev = &DN->l;
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = SECITEM_CopyItem(arena, &DN->derDirectoryName, &cert->derSubject);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME,
+ &altNameExtension);
+ if (rv != SECSuccess) {
+ return DN;
+ }
+ altName = CERT_DecodeAltNameExtension(arena, &altNameExtension);
+ PORT_Free(altNameExtension.data);
+ DN = cert_CombineNamesLists(DN, altName);
+ return DN;
+loser:
+
+ return NULL;
+}
+
+static SECStatus
+compareNameToConstraint(char *name, char *constraint, PRBool substring)
+{
+ SECStatus rv;
+
+ if (*constraint == '\0' && *name == '\0') {
+ return SECSuccess;
+ }
+ if (*constraint == '*') {
+ return compareNameToConstraint(name, constraint + 1, PR_TRUE);
+ }
+ if (substring) {
+ if (*constraint == '\0') {
+ return SECSuccess;
+ }
+ while (*name != *constraint) {
+ if (*name == '\0') {
+ return SECFailure;
+ }
+ name++;
+ }
+ rv = compareNameToConstraint(name + 1, constraint + 1, PR_FALSE);
+ if (rv == SECSuccess) {
+ return rv;
+ }
+ name++;
+ } else {
+ if (*name == *constraint) {
+ name++;
+ constraint++;
+ } else {
+ return SECFailure;
+ }
+ }
+ return compareNameToConstraint(name, constraint, substring);
+}
+
+SECStatus
+cert_CompareNameWithConstraints(CERTGeneralName *name,
+ CERTNameConstraint *constraints,
+ PRBool excluded)
+{
+ SECStatus rv = SECSuccess;
+ char *nameString = NULL;
+ char *constraintString = NULL;
+ int start;
+ int end;
+ int tag;
+ CERTRDN **nameRDNS, *nameRDN;
+ CERTRDN **constraintRDNS, *constraintRDN;
+ CERTAVA **nameAVAS, *nameAVA;
+ CERTAVA **constraintAVAS, *constraintAVA;
+ CERTNameConstraint *current;
+ SECItem *avaValue;
+ CERTName constraintName;
+ CERTName certName;
+ SECComparison status = SECEqual;
+ PRArenaPool *certNameArena;
+ PRArenaPool *constraintNameArena;
+
+ certName.arena = NULL;
+ certName.rdns = NULL;
+ constraintName.arena = NULL;
+ constraintName.rdns = NULL;
+ if (constraints != NULL) {
+ current = constraints;
+ if (name->type == certDirectoryName) {
+ certNameArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ CERT_CopyName(certNameArena, &certName, &name->name.directoryName);
+ nameRDNS = certName.rdns;
+ for (;;) {
+ nameRDN = *nameRDNS++;
+ nameAVAS = nameRDN->avas;
+ for(;;) {
+ nameAVA = *nameAVAS++;
+ tag = CERT_GetAVATag(nameAVA);
+ if ( tag == SEC_OID_PKCS9_EMAIL_ADDRESS ||
+ tag == SEC_OID_RFC1274_MAIL) {
+ avaValue = CERT_DecodeAVAValue(&nameAVA->value);
+ nameString = (char*)PORT_ZAlloc(avaValue->len + 1);
+ nameString = PORT_Strncpy(nameString, (char *) avaValue->data, avaValue->len);
+ start = 0;
+ while(nameString[start] != '@' && nameString[start + 1] != '\0') {
+ start++;
+ }
+ start++;
+ do{
+ if (current->name.type == certRFC822Name) {
+ constraintString = (char*)PORT_ZAlloc(current->name.name.other.len + 1);
+ constraintString = PORT_Strncpy(constraintString,
+ (char *) current->name.name.other.data,
+ current->name.name.other.len);
+ rv = compareNameToConstraint(nameString + start, constraintString,
+ PR_FALSE);
+
+ if (constraintString != NULL) {
+ PORT_Free(constraintString);
+ constraintString = NULL;
+ }
+ if (nameString != NULL) {
+ PORT_Free(nameString);
+ nameString = NULL;
+ }
+ if (rv == SECSuccess && excluded == PR_TRUE) {
+ goto found;
+ }
+ if (rv == SECSuccess && excluded == PR_FALSE) {
+ break;
+ }
+ }
+ current = cert_get_next_name_constraint(current);
+ } while (current != constraints);
+ }
+ if (rv != SECSuccess && excluded == PR_FALSE) {
+ goto loser;
+ }
+ if (*nameAVAS == NULL) {
+ break;
+ }
+ }
+ if (*nameRDNS == NULL) {
+ break;
+ }
+ }
+ }
+ current = constraints;
+ do {
+ switch (name->type) {
+ case certDNSName:
+ nameString = (char*)PORT_ZAlloc(name->name.other.len + 1);
+ nameString = PORT_Strncpy(nameString, (char *) name->name.other.data,
+ name->name.other.len);
+ constraintString = (char*)PORT_ZAlloc(current->name.name.other.len + 1);
+ constraintString = PORT_Strncpy(constraintString,
+ (char *) current->name.name.other.data,
+ current->name.name.other.len);
+ rv = compareNameToConstraint(nameString, constraintString, PR_FALSE);
+ if (nameString != NULL) {
+ PORT_Free(nameString);
+ }
+ if (constraintString != NULL) {
+ PORT_Free(constraintString);
+ }
+ break;
+ case certRFC822Name:
+ nameString = (char*)PORT_ZAlloc(name->name.other.len + 1);
+ nameString = PORT_Strncpy(nameString, (char *) name->name.other.data,
+ name->name.other.len);
+ start = 0;
+ while(nameString[start] != '@' && nameString[start + 1] != '\0') {
+ start++;
+ }
+ start++;
+ constraintString = (char*)PORT_ZAlloc(current->name.name.other.len + 1);
+ constraintString = PORT_Strncpy(constraintString,
+ (char *) current->name.name.other.data,
+ current->name.name.other.len);
+ rv = compareNameToConstraint(nameString + start, constraintString, PR_FALSE);
+ if (nameString != NULL) {
+ PORT_Free(nameString);
+ }
+ if (constraintString != NULL) {
+ PORT_Free(constraintString);
+ }
+ break;
+ case certURI:
+ nameString = (char*)PORT_ZAlloc(name->name.other.len + 1);
+ nameString = PORT_Strncpy(nameString, (char *) name->name.other.data,
+ name->name.other.len);
+ start = 0;
+ while(PORT_Strncmp(nameString + start, "://", 3) != 0 &&
+ nameString[start + 3] != '\0') {
+ start++;
+ }
+ start +=3;
+ end = 0;
+ while(nameString[start + end] != '/' &&
+ nameString[start + end] != '\0') {
+ end++;
+ }
+ nameString[start + end] = '\0';
+ constraintString = (char*)PORT_ZAlloc(current->name.name.other.len + 1);
+ constraintString = PORT_Strncpy(constraintString,
+ (char *) current->name.name.other.data,
+ current->name.name.other.len);
+ rv = compareNameToConstraint(nameString + start, constraintString, PR_FALSE);
+ if (nameString != NULL) {
+ PORT_Free(nameString);
+ }
+ if (constraintString != NULL) {
+ PORT_Free(constraintString);
+ }
+ break;
+ case certDirectoryName:
+ if (current->name.type == certDirectoryName) {
+ constraintNameArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ CERT_CopyName(constraintNameArena, &constraintName, &current->name.name.directoryName);
+ constraintRDNS = constraintName.rdns;
+ for (;;) {
+ constraintRDN = *constraintRDNS++;
+ constraintAVAS = constraintRDN->avas;
+ for(;;) {
+ constraintAVA = *constraintAVAS++;
+ certNameArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ CERT_CopyName(certNameArena, &certName, &name->name.directoryName);
+ nameRDNS = certName.rdns;
+ for (;;) {
+ nameRDN = *nameRDNS++;
+ nameAVAS = nameRDN->avas++;
+ for(;;) {
+ nameAVA = *nameAVAS++;
+ status = CERT_CompareAVA(constraintAVA, nameAVA);
+ if (status == SECEqual || *nameAVAS == NULL) {
+ break;
+ }
+ }
+ if (status == SECEqual || *nameRDNS == NULL) {
+ break;
+ }
+ }
+ if (status != SECEqual || *constraintAVAS == NULL) {
+ break;
+ }
+ }
+ if (status != SECEqual || *constraintRDNS == NULL) {
+ break;
+ }
+ }
+ if (status == SECEqual) {
+ if (excluded == PR_FALSE) {
+ goto found;
+ } else {
+ goto loser;
+ }
+ }
+ break;
+ } else if (current->name.type == certRFC822Name) {
+ current = cert_get_next_name_constraint(current);
+ continue;
+ }
+ default:
+ /* other types are not supported */
+ if (excluded) {
+ goto found;
+ } else {
+ goto loser;
+ }
+ }
+ if (rv == SECSuccess && status == SECEqual) {
+ goto found;
+ }
+ current = cert_get_next_name_constraint(current);
+ } while (current !=constraints);
+ } else {
+ goto found;
+ }
+loser:
+ if (certName.arena) {
+ CERT_DestroyName(&certName);
+ }
+ if (constraintName.arena) {
+ CERT_DestroyName(&constraintName);
+ }
+ return SECFailure;
+found:
+ if (certName.arena) {
+ CERT_DestroyName(&certName);
+ }
+ if (constraintName.arena) {
+ CERT_DestroyName(&constraintName);
+ }
+ return SECSuccess;
+}
+
+
+CERTCertificate *
+CERT_CompareNameSpace(CERTCertificate *cert,
+ CERTGeneralName *namesList,
+ SECItem *namesListIndex,
+ PRArenaPool *arena,
+ CERTCertDBHandle *handle)
+{
+ SECStatus rv;
+ SECItem constraintsExtension;
+ CERTNameConstraints *constraints;
+ CERTGeneralName *currentName;
+ int count = 0;
+ CERTNameConstraint *matchingConstraints;
+ CERTCertificate *badCert = NULL;
+
+ rv = CERT_FindCertExtension(cert, SEC_OID_X509_NAME_CONSTRAINTS, &constraintsExtension);
+ if (rv != SECSuccess) {
+ return NULL;
+ }
+ constraints = cert_DecodeNameConstraints(arena, &constraintsExtension);
+ currentName = namesList;
+ if (constraints == NULL) {
+ goto loser;
+ }
+ do {
+ if (constraints->excluded != NULL) {
+ rv = CERT_GetNameConstriantByType(constraints->excluded, currentName->type,
+ &matchingConstraints, arena);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ if (matchingConstraints != NULL) {
+ rv = cert_CompareNameWithConstraints(currentName, matchingConstraints,
+ PR_TRUE);
+ if (rv != SECFailure) {
+ goto loser;
+ }
+ }
+ }
+ if (constraints->permited != NULL) {
+ rv = CERT_GetNameConstriantByType(constraints->permited, currentName->type,
+ &matchingConstraints, arena);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ if (matchingConstraints != NULL) {
+ rv = cert_CompareNameWithConstraints(currentName, matchingConstraints,
+ PR_FALSE);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ } else {
+ goto loser;
+ }
+ }
+ currentName = cert_get_next_general_name(currentName);
+ count ++;
+ } while (currentName != namesList);
+ return NULL;
+loser:
+ badCert = CERT_FindCertByName (handle, &namesListIndex[count]);
+ return badCert;
+}
+
+
+
+/* Search the cert for an X509_SUBJECT_ALT_NAME extension.
+** ASN1 Decode it into a list of alternate names.
+** Search the list of alternate names for one with the NETSCAPE_NICKNAME OID.
+** ASN1 Decode that name. Turn the result into a zString.
+** Look for duplicate nickname already in the certdb.
+** If one is found, create a nickname string that is not a duplicate.
+*/
+char *
+CERT_GetNickName(CERTCertificate *cert,
+ CERTCertDBHandle *handle,
+ PRArenaPool *nicknameArena)
+{
+ CERTGeneralName *current;
+ CERTGeneralName *names;
+ char *nickname = NULL;
+ char *returnName = NULL;
+ char *basename = NULL;
+ PRArenaPool *arena = NULL;
+ CERTCertificate *tmpcert;
+ SECStatus rv;
+ int count;
+ int found = 0;
+ SECItem altNameExtension;
+ SECItem nick;
+
+ if (handle == NULL) {
+ handle = CERT_GetDefaultCertDB();
+ }
+ altNameExtension.data = NULL;
+ rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME,
+ &altNameExtension);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ goto loser;
+ }
+ names = CERT_DecodeAltNameExtension(arena, &altNameExtension);
+ if (names == NULL) {
+ goto loser;
+ }
+ current = names;
+ do {
+ if (current->type == certOtherName &&
+ SECOID_FindOIDTag(&current->name.OthName.oid) ==
+ SEC_OID_NETSCAPE_NICKNAME) {
+ found = 1;
+ break;
+ }
+ current = cert_get_next_general_name(current);
+ } while (current != names);
+ if (!found)
+ goto loser;
+
+ rv = SEC_ASN1DecodeItem(arena, &nick, SEC_IA5StringTemplate,
+ &current->name.OthName.name);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* make a null terminated string out of nick, with room enough at
+ ** the end to add on a number of up to 21 digits in length, (a signed
+ ** 64-bit number in decimal) plus a space and a "#".
+ */
+ nickname = (char*)PORT_ZAlloc(nick.len + 24);
+ if (!nickname)
+ goto loser;
+ PORT_Strncpy(nickname, (char *)nick.data, nick.len);
+
+ /* Don't let this cert's nickname duplicate one already in the DB.
+ ** If it does, create a variant of the nickname that doesn't.
+ */
+ count = 0;
+ while ((tmpcert = CERT_FindCertByNickname(handle, nickname)) != NULL) {
+ CERT_DestroyCertificate(tmpcert);
+ if (!basename) {
+ basename = PORT_Strdup(nickname);
+ if (!basename)
+ goto loser;
+ }
+ count++;
+ sprintf(nickname, "%s #%d", basename, count);
+ }
+
+ /* success */
+ if (nicknameArena) {
+ returnName = PORT_ArenaStrdup(nicknameArena, nickname);
+ } else {
+ returnName = nickname;
+ nickname = NULL;
+ }
+loser:
+ if (arena != NULL)
+ PORT_FreeArena(arena, PR_FALSE);
+ if (nickname)
+ PORT_Free(nickname);
+ if (basename)
+ PORT_Free(basename);
+ if (altNameExtension.data)
+ PORT_Free(altNameExtension.data);
+ return returnName;
+}
+
+
+SECStatus
+CERT_CompareGeneralName(CERTGeneralName *a, CERTGeneralName *b)
+{
+ CERTGeneralName *currentA;
+ CERTGeneralName *currentB;
+ PRBool found;
+
+ currentA = a;
+ currentB = b;
+ if (a != NULL) {
+ do {
+ if (currentB == NULL) {
+ return SECFailure;
+ }
+ currentB = cert_get_next_general_name(currentB);
+ currentA = cert_get_next_general_name(currentA);
+ } while (currentA != a);
+ }
+ if (currentB != b) {
+ return SECFailure;
+ }
+ currentA = a;
+ do {
+ currentB = b;
+ found = PR_FALSE;
+ do {
+ if (currentB->type == currentA->type) {
+ switch (currentB->type) {
+ case certDNSName:
+ case certEDIPartyName:
+ case certIPAddress:
+ case certRegisterID:
+ case certRFC822Name:
+ case certX400Address:
+ case certURI:
+ if (SECITEM_CompareItem(&currentA->name.other,
+ &currentB->name.other)
+ == SECEqual) {
+ found = PR_TRUE;
+ }
+ break;
+ case certOtherName:
+ if (SECITEM_CompareItem(&currentA->name.OthName.oid,
+ &currentB->name.OthName.oid)
+ == SECEqual &&
+ SECITEM_CompareItem(&currentA->name.OthName.name,
+ &currentB->name.OthName.name)
+ == SECEqual) {
+ found = PR_TRUE;
+ }
+ break;
+ case certDirectoryName:
+ if (CERT_CompareName(&currentA->name.directoryName,
+ &currentB->name.directoryName)
+ == SECEqual) {
+ found = PR_TRUE;
+ }
+ }
+
+ }
+ currentB = cert_get_next_general_name(currentB);
+ } while (currentB != b && found != PR_TRUE);
+ if (found != PR_TRUE) {
+ return SECFailure;
+ }
+ currentA = cert_get_next_general_name(currentA);
+ } while (currentA != a);
+ return SECSuccess;
+}
+
+SECStatus
+CERT_CompareGeneralNameLists(CERTGeneralNameList *a, CERTGeneralNameList *b)
+{
+ SECStatus rv;
+
+ if (a == b) {
+ return SECSuccess;
+ }
+ if (a != NULL && b != NULL) {
+ PZ_Lock(a->lock);
+ PZ_Lock(b->lock);
+ rv = CERT_CompareGeneralName(a->name, b->name);
+ PZ_Unlock(a->lock);
+ PZ_Unlock(b->lock);
+ } else {
+ rv = SECFailure;
+ }
+ return rv;
+}
+
+void *
+CERT_GetGeneralNameFromListByType(CERTGeneralNameList *list,
+ CERTGeneralNameType type,
+ PRArenaPool *arena)
+{
+ CERTName *name = NULL;
+ SECItem *item = NULL;
+ OtherName *other = NULL;
+ OtherName *tmpOther = NULL;
+ void *data;
+
+ PZ_Lock(list->lock);
+ data = CERT_GetGeneralNameByType(list->name, type, PR_FALSE);
+ if (data != NULL) {
+ switch (type) {
+ case certDNSName:
+ case certEDIPartyName:
+ case certIPAddress:
+ case certRegisterID:
+ case certRFC822Name:
+ case certX400Address:
+ case certURI:
+ if (arena != NULL) {
+ item = (SECItem *)PORT_ArenaAlloc(arena, sizeof(SECItem));
+ if (item != NULL) {
+ SECITEM_CopyItem(arena, item, (SECItem *) data);
+ }
+ } else {
+ item = SECITEM_DupItem((SECItem *) data);
+ }
+ PZ_Unlock(list->lock);
+ return item;
+ case certOtherName:
+ other = (OtherName *) data;
+ if (arena != NULL) {
+ tmpOther = (OtherName *)PORT_ArenaAlloc(arena,
+ sizeof(OtherName));
+ } else {
+ tmpOther = (OtherName *) PORT_Alloc(sizeof(OtherName));
+ }
+ if (tmpOther != NULL) {
+ SECITEM_CopyItem(arena, &tmpOther->oid, &other->oid);
+ SECITEM_CopyItem(arena, &tmpOther->name, &other->name);
+ }
+ PZ_Unlock(list->lock);
+ return tmpOther;
+ case certDirectoryName:
+ if (arena == NULL) {
+ PZ_Unlock(list->lock);
+ return NULL;
+ } else {
+ name = (CERTName *) PORT_ArenaZAlloc(list->arena,
+ sizeof(CERTName));
+ if (name != NULL) {
+ CERT_CopyName(arena, name, (CERTName *) data);
+ }
+ PZ_Unlock(list->lock);
+ return name;
+ }
+ }
+ }
+ PZ_Unlock(list->lock);
+ return NULL;
+}
+
+void
+CERT_AddGeneralNameToList(CERTGeneralNameList *list,
+ CERTGeneralNameType type,
+ void *data, SECItem *oid)
+{
+ CERTGeneralName *name;
+
+ if (list != NULL && data != NULL) {
+ PZ_Lock(list->lock);
+ name = (CERTGeneralName *)
+ PORT_ArenaZAlloc(list->arena, sizeof(CERTGeneralName));
+ name->type = type;
+ switch (type) {
+ case certDNSName:
+ case certEDIPartyName:
+ case certIPAddress:
+ case certRegisterID:
+ case certRFC822Name:
+ case certX400Address:
+ case certURI:
+ SECITEM_CopyItem(list->arena, &name->name.other, (SECItem *)data);
+ break;
+ case certOtherName:
+ SECITEM_CopyItem(list->arena, &name->name.OthName.name,
+ (SECItem *) data);
+ SECITEM_CopyItem(list->arena, &name->name.OthName.oid,
+ oid);
+ break;
+ case certDirectoryName:
+ CERT_CopyName(list->arena, &name->name.directoryName,
+ (CERTName *) data);
+ break;
+ }
+ name->l.prev = name->l.next = &name->l;
+ list->name = cert_CombineNamesLists(list->name, name);
+ list->len++;
+ PZ_Unlock(list->lock);
+ }
+ return;
+}
diff --git a/security/nss/lib/certdb/genname.h b/security/nss/lib/certdb/genname.h
new file mode 100644
index 000000000..8e3a58619
--- /dev/null
+++ b/security/nss/lib/certdb/genname.h
@@ -0,0 +1,125 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+#ifndef _GENAME_H_
+#define _GENAME_H_
+
+#include "plarena.h"
+#include "seccomon.h"
+#include "secoidt.h"
+#include "secasn1.h"
+#include "secder.h"
+#include "certt.h"
+
+/************************************************************************/
+SEC_BEGIN_PROTOS
+
+extern const SEC_ASN1Template CERT_GeneralNamesTemplate[];
+
+extern CERTGeneralName *
+cert_get_next_general_name(CERTGeneralName *current);
+
+extern CERTGeneralName *
+cert_get_prev_general_name(CERTGeneralName *current);
+
+extern SECItem *
+CERT_EncodeGeneralName(CERTGeneralName *genName, SECItem *dest,
+ PRArenaPool *arena);
+
+extern SECItem **
+cert_EncodeGeneralNames(PRArenaPool *arena, CERTGeneralName *names);
+
+extern CERTGeneralName *
+CERT_DecodeGeneralName(PRArenaPool *arena, SECItem *encodedName,
+ CERTGeneralName *genName);
+
+extern CERTGeneralName *
+cert_DecodeGeneralNames(PRArenaPool *arena, SECItem **encodedGenName);
+
+extern SECStatus
+cert_DestroyGeneralNames(CERTGeneralName *name);
+
+extern SECStatus
+cert_EncodeNameConstraints(CERTNameConstraints *constraints, PRArenaPool *arena,
+ SECItem *dest);
+
+extern CERTNameConstraints *
+cert_DecodeNameConstraints(PRArenaPool *arena, SECItem *encodedConstraints);
+
+extern CERTGeneralName *
+cert_CombineNamesLists(CERTGeneralName *list1, CERTGeneralName *list2);
+
+extern CERTNameConstraint *
+cert_CombineConstraintsLists(CERTNameConstraint *list1, CERTNameConstraint *list2);
+
+SECStatus
+CERT_CompareGeneralName(CERTGeneralName *a, CERTGeneralName *b);
+
+SECStatus
+CERT_CopyGeneralName(PRArenaPool *arena,
+ CERTGeneralName *dest,
+ CERTGeneralName *src);
+
+/* General Name Lists are a thread safe, reference counting layer to
+ * general names */
+
+void
+CERT_DestroyGeneralNameList(CERTGeneralNameList *list);
+
+CERTGeneralNameList *
+CERT_CreateGeneralNameList(CERTGeneralName *name);
+
+SECStatus
+CERT_CompareGeneralNameLists(CERTGeneralNameList *a, CERTGeneralNameList *b);
+
+void *
+CERT_GetGeneralNameFromListByType(CERTGeneralNameList *list,
+ CERTGeneralNameType type,
+ PRArenaPool *arena);
+
+void
+CERT_AddGeneralNameToList(CERTGeneralNameList *list,
+ CERTGeneralNameType type,
+ void *data, SECItem *oid);
+
+
+CERTGeneralNameList *
+CERT_DupGeneralNameList(CERTGeneralNameList *list);
+
+
+int
+CERT_GetNamesLength(CERTGeneralName *names);
+/************************************************************************/
+SEC_END_PROTOS
+
+#endif
diff --git a/security/nss/lib/certdb/manifest.mn b/security/nss/lib/certdb/manifest.mn
new file mode 100644
index 000000000..944d38a55
--- /dev/null
+++ b/security/nss/lib/certdb/manifest.mn
@@ -0,0 +1,68 @@
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Netscape security libraries.
+#
+# The Initial Developer of the Original Code is Netscape
+# Communications Corporation. Portions created by Netscape are
+# Copyright (C) 1994-2000 Netscape Communications Corporation. All
+# Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the
+# terms of the GNU General Public License Version 2 or later (the
+# "GPL"), in which case the provisions of the GPL are applicable
+# instead of those above. If you wish to allow use of your
+# version of this file only under the terms of the GPL and not to
+# allow others to use your version of this file under the MPL,
+# indicate your decision by deleting the provisions above and
+# replace them with the notice and other provisions required by
+# the GPL. If you do not delete the provisions above, a recipient
+# may use your version of this file under either the MPL or the
+# GPL.
+#
+CORE_DEPTH = ../../..
+
+EXPORTS = \
+ cert.h \
+ certt.h \
+ certdb.h \
+ $(NULL)
+
+PRIVATE_EXPORTS = \
+ genname.h \
+ xconst.h \
+ certxutl.h \
+ certi.h \
+ $(NULL)
+
+MODULE = nss
+
+CSRCS = \
+ alg1485.c \
+ certdb.c \
+ certv3.c \
+ certxutl.c \
+ crl.c \
+ genname.c \
+ stanpcertdb.c \
+ polcyxtn.c \
+ secname.c \
+ xauthkid.c \
+ xbsconst.c \
+ xconst.c \
+ $(NULL)
+
+REQUIRES = dbm
+
+LIBRARY_NAME = certdb
+
diff --git a/security/nss/lib/certdb/polcyxtn.c b/security/nss/lib/certdb/polcyxtn.c
new file mode 100644
index 000000000..41302f039
--- /dev/null
+++ b/security/nss/lib/certdb/polcyxtn.c
@@ -0,0 +1,565 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+ * Support for various policy related extensions
+ *
+ * $Id$
+ */
+
+#include "seccomon.h"
+#include "secport.h"
+#include "secder.h"
+#include "cert.h"
+#include "secoid.h"
+#include "secasn1.h"
+#include "secerr.h"
+#include "nspr.h"
+
+const SEC_ASN1Template CERT_NoticeReferenceTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTNoticeReference) },
+/* NOTE: this should be a choice */
+ { SEC_ASN1_IA5_STRING,
+ offsetof(CERTNoticeReference, organization) },
+ { SEC_ASN1_SEQUENCE_OF,
+ offsetof(CERTNoticeReference, noticeNumbers),
+ SEC_IntegerTemplate },
+ { 0 }
+};
+
+/* this template can not be encoded because of the option inline */
+const SEC_ASN1Template CERT_UserNoticeTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTUserNotice) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED,
+ offsetof(CERTUserNotice, derNoticeReference) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
+ offsetof(CERTUserNotice, displayText) },
+ { 0 }
+};
+
+const SEC_ASN1Template CERT_PolicyQualifierTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTPolicyQualifier) },
+ { SEC_ASN1_OBJECT_ID,
+ offsetof(CERTPolicyQualifier, qualifierID) },
+ { SEC_ASN1_ANY,
+ offsetof(CERTPolicyQualifier, qualifierValue) },
+ { 0 }
+};
+
+const SEC_ASN1Template CERT_PolicyInfoTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTPolicyInfo) },
+ { SEC_ASN1_OBJECT_ID,
+ offsetof(CERTPolicyInfo, policyID) },
+ { SEC_ASN1_SEQUENCE_OF,
+ offsetof(CERTPolicyInfo, policyQualifiers),
+ CERT_PolicyQualifierTemplate },
+ { 0 }
+};
+
+const SEC_ASN1Template CERT_CertificatePoliciesTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF,
+ offsetof(CERTCertificatePolicies, policyInfos),
+ CERT_PolicyInfoTemplate, sizeof(CERTCertificatePolicies) }
+};
+
+static void
+breakLines(char *string)
+{
+ char *tmpstr;
+ char *lastspace = NULL;
+ int curlen = 0;
+ int c;
+
+ tmpstr = string;
+
+ while ( ( c = *tmpstr ) != '\0' ) {
+ switch ( c ) {
+ case ' ':
+ lastspace = tmpstr;
+ break;
+ case '\n':
+ lastspace = NULL;
+ curlen = 0;
+ break;
+ }
+
+ if ( ( curlen >= 55 ) && ( lastspace != NULL ) ) {
+ *lastspace = '\n';
+ curlen = ( tmpstr - lastspace );
+ lastspace = NULL;
+ }
+
+ curlen++;
+ tmpstr++;
+ }
+
+ return;
+}
+
+CERTCertificatePolicies *
+CERT_DecodeCertificatePoliciesExtension(SECItem *extnValue)
+{
+ PRArenaPool *arena = NULL;
+ SECStatus rv;
+ CERTCertificatePolicies *policies;
+ CERTPolicyInfo **policyInfos, *policyInfo;
+ CERTPolicyQualifier **policyQualifiers, *policyQualifier;
+ SECItem newExtnValue;
+
+ /* make a new arena */
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+
+ if ( !arena ) {
+ goto loser;
+ }
+
+ /* allocate the certifiate policies structure */
+ policies = (CERTCertificatePolicies *)
+ PORT_ArenaZAlloc(arena, sizeof(CERTCertificatePolicies));
+
+ if ( policies == NULL ) {
+ goto loser;
+ }
+
+ policies->arena = arena;
+
+ /* copy the DER into the arena, since Quick DER returns data that points
+ into the DER input, which may get freed by the caller */
+ rv = SECITEM_CopyItem(arena, &newExtnValue, extnValue);
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ /* decode the policy info */
+ rv = SEC_QuickDERDecodeItem(arena, policies, CERT_CertificatePoliciesTemplate,
+ &newExtnValue);
+
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ /* initialize the oid tags */
+ policyInfos = policies->policyInfos;
+ while (*policyInfos != NULL ) {
+ policyInfo = *policyInfos;
+ policyInfo->oid = SECOID_FindOIDTag(&policyInfo->policyID);
+ policyQualifiers = policyInfo->policyQualifiers;
+ while ( *policyQualifiers != NULL ) {
+ policyQualifier = *policyQualifiers;
+ policyQualifier->oid =
+ SECOID_FindOIDTag(&policyQualifier->qualifierID);
+ policyQualifiers++;
+ }
+ policyInfos++;
+ }
+
+ return(policies);
+
+loser:
+ if ( arena != NULL ) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ return(NULL);
+}
+
+void
+CERT_DestroyCertificatePoliciesExtension(CERTCertificatePolicies *policies)
+{
+ if ( policies != NULL ) {
+ PORT_FreeArena(policies->arena, PR_FALSE);
+ }
+ return;
+}
+
+
+CERTUserNotice *
+CERT_DecodeUserNotice(SECItem *noticeItem)
+{
+ PRArenaPool *arena = NULL;
+ SECStatus rv;
+ CERTUserNotice *userNotice;
+ SECItem newNoticeItem;
+
+ /* make a new arena */
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+
+ if ( !arena ) {
+ goto loser;
+ }
+
+ /* allocate the userNotice structure */
+ userNotice = (CERTUserNotice *)PORT_ArenaZAlloc(arena,
+ sizeof(CERTUserNotice));
+
+ if ( userNotice == NULL ) {
+ goto loser;
+ }
+
+ userNotice->arena = arena;
+
+ /* copy the DER into the arena, since Quick DER returns data that points
+ into the DER input, which may get freed by the caller */
+ rv = SECITEM_CopyItem(arena, &newNoticeItem, noticeItem);
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ /* decode the user notice */
+ rv = SEC_QuickDERDecodeItem(arena, userNotice, CERT_UserNoticeTemplate,
+ &newNoticeItem);
+
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ if (userNotice->derNoticeReference.data != NULL) {
+ /* sigh, the asn1 parser stripped the sequence encoding, re add it
+ * before we decode.
+ */
+ SECItem tmpbuf;
+ int newBytes;
+
+ newBytes = SEC_ASN1LengthLength(userNotice->derNoticeReference.len)+1;
+ tmpbuf.len = newBytes + userNotice->derNoticeReference.len;
+ tmpbuf.data = PORT_ArenaZAlloc(arena, tmpbuf.len);
+ if (tmpbuf.data == NULL) {
+ goto loser;
+ }
+ tmpbuf.data[0] = SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED;
+ SEC_ASN1EncodeLength(&tmpbuf.data[1],userNotice->derNoticeReference.len);
+ PORT_Memcpy(&tmpbuf.data[newBytes],userNotice->derNoticeReference.data,
+ userNotice->derNoticeReference.len);
+
+ /* OK, no decode it */
+ rv = SEC_QuickDERDecodeItem(arena, &userNotice->noticeReference,
+ CERT_NoticeReferenceTemplate, &tmpbuf);
+
+ PORT_Free(tmpbuf.data); tmpbuf.data = NULL;
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+ }
+
+ return(userNotice);
+
+loser:
+ if ( arena != NULL ) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ return(NULL);
+}
+
+void
+CERT_DestroyUserNotice(CERTUserNotice *userNotice)
+{
+ if ( userNotice != NULL ) {
+ PORT_FreeArena(userNotice->arena, PR_FALSE);
+ }
+ return;
+}
+
+static CERTPolicyStringCallback policyStringCB = NULL;
+static void *policyStringCBArg = NULL;
+
+void
+CERT_SetCAPolicyStringCallback(CERTPolicyStringCallback cb, void *cbarg)
+{
+ policyStringCB = cb;
+ policyStringCBArg = cbarg;
+ return;
+}
+
+char *
+stringFromUserNotice(SECItem *noticeItem)
+{
+ SECItem *org;
+ unsigned int len, headerlen;
+ char *stringbuf;
+ CERTUserNotice *userNotice;
+ char *policystr;
+ char *retstr = NULL;
+ SECItem *displayText;
+ SECItem **noticeNumbers;
+ unsigned int strnum;
+
+ /* decode the user notice */
+ userNotice = CERT_DecodeUserNotice(noticeItem);
+ if ( userNotice == NULL ) {
+ return(NULL);
+ }
+
+ org = &userNotice->noticeReference.organization;
+ if ( (org->len != 0 ) && ( policyStringCB != NULL ) ) {
+ /* has a noticeReference */
+
+ /* extract the org string */
+ len = org->len;
+ stringbuf = (char*)PORT_Alloc(len + 1);
+ if ( stringbuf != NULL ) {
+ PORT_Memcpy(stringbuf, org->data, len);
+ stringbuf[len] = '\0';
+
+ noticeNumbers = userNotice->noticeReference.noticeNumbers;
+ while ( *noticeNumbers != NULL ) {
+ /* XXX - only one byte integers right now*/
+ strnum = (*noticeNumbers)->data[0];
+ policystr = (* policyStringCB)(stringbuf,
+ strnum,
+ policyStringCBArg);
+ if ( policystr != NULL ) {
+ if ( retstr != NULL ) {
+ retstr = PR_sprintf_append(retstr, "\n%s", policystr);
+ } else {
+ retstr = PR_sprintf_append(retstr, "%s", policystr);
+ }
+
+ PORT_Free(policystr);
+ }
+
+ noticeNumbers++;
+ }
+
+ PORT_Free(stringbuf);
+ }
+ }
+
+ if ( retstr == NULL ) {
+ if ( userNotice->displayText.len != 0 ) {
+ displayText = &userNotice->displayText;
+
+ if ( displayText->len > 2 ) {
+ if ( displayText->data[0] == SEC_ASN1_VISIBLE_STRING ) {
+ headerlen = 2;
+ if ( displayText->data[1] & 0x80 ) {
+ /* multibyte length */
+ headerlen += ( displayText->data[1] & 0x7f );
+ }
+
+ len = displayText->len - headerlen;
+ retstr = (char*)PORT_Alloc(len + 1);
+ if ( retstr != NULL ) {
+ PORT_Memcpy(retstr, &displayText->data[headerlen],len);
+ retstr[len] = '\0';
+ }
+ }
+ }
+ }
+ }
+
+ CERT_DestroyUserNotice(userNotice);
+
+ return(retstr);
+}
+
+char *
+CERT_GetCertCommentString(CERTCertificate *cert)
+{
+ char *retstring = NULL;
+ SECStatus rv;
+ SECItem policyItem;
+ CERTCertificatePolicies *policies = NULL;
+ CERTPolicyInfo **policyInfos;
+ CERTPolicyQualifier **policyQualifiers, *qualifier;
+
+ policyItem.data = NULL;
+
+ rv = CERT_FindCertExtension(cert, SEC_OID_X509_CERTIFICATE_POLICIES,
+ &policyItem);
+ if ( rv != SECSuccess ) {
+ goto nopolicy;
+ }
+
+ policies = CERT_DecodeCertificatePoliciesExtension(&policyItem);
+ if ( policies == NULL ) {
+ goto nopolicy;
+ }
+
+ policyInfos = policies->policyInfos;
+ /* search through policyInfos looking for the verisign policy */
+ while (*policyInfos != NULL ) {
+ if ( (*policyInfos)->oid == SEC_OID_VERISIGN_USER_NOTICES ) {
+ policyQualifiers = (*policyInfos)->policyQualifiers;
+ /* search through the policy qualifiers looking for user notice */
+ while ( *policyQualifiers != NULL ) {
+ qualifier = *policyQualifiers;
+ if ( qualifier->oid == SEC_OID_PKIX_USER_NOTICE_QUALIFIER ) {
+ retstring =
+ stringFromUserNotice(&qualifier->qualifierValue);
+ break;
+ }
+
+ policyQualifiers++;
+ }
+ break;
+ }
+ policyInfos++;
+ }
+
+nopolicy:
+ if ( policyItem.data != NULL ) {
+ PORT_Free(policyItem.data);
+ }
+
+ if ( policies != NULL ) {
+ CERT_DestroyCertificatePoliciesExtension(policies);
+ }
+
+ if ( retstring == NULL ) {
+ retstring = CERT_FindNSStringExtension(cert,
+ SEC_OID_NS_CERT_EXT_COMMENT);
+ }
+
+ if ( retstring != NULL ) {
+ breakLines(retstring);
+ }
+
+ return(retstring);
+}
+
+
+const SEC_ASN1Template CERT_OidSeqTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF,
+ offsetof(CERTOidSequence, oids),
+ SEC_ObjectIDTemplate }
+};
+
+CERTOidSequence *
+CERT_DecodeOidSequence(SECItem *seqItem)
+{
+ PRArenaPool *arena = NULL;
+ SECStatus rv;
+ CERTOidSequence *oidSeq;
+ SECItem newSeqItem;
+
+ /* make a new arena */
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+
+ if ( !arena ) {
+ goto loser;
+ }
+
+ /* allocate the userNotice structure */
+ oidSeq = (CERTOidSequence *)PORT_ArenaZAlloc(arena,
+ sizeof(CERTOidSequence));
+
+ if ( oidSeq == NULL ) {
+ goto loser;
+ }
+
+ oidSeq->arena = arena;
+
+ /* copy the DER into the arena, since Quick DER returns data that points
+ into the DER input, which may get freed by the caller */
+ rv = SECITEM_CopyItem(arena, &newSeqItem, seqItem);
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ /* decode the user notice */
+ rv = SEC_QuickDERDecodeItem(arena, oidSeq, CERT_OidSeqTemplate, &newSeqItem);
+
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ return(oidSeq);
+
+loser:
+ return(NULL);
+}
+
+
+void
+CERT_DestroyOidSequence(CERTOidSequence *oidSeq)
+{
+ if ( oidSeq != NULL ) {
+ PORT_FreeArena(oidSeq->arena, PR_FALSE);
+ }
+ return;
+}
+
+PRBool
+CERT_GovtApprovedBitSet(CERTCertificate *cert)
+{
+ SECStatus rv;
+ SECItem extItem;
+ CERTOidSequence *oidSeq = NULL;
+ PRBool ret;
+ SECItem **oids;
+ SECItem *oid;
+ SECOidTag oidTag;
+
+ extItem.data = NULL;
+ rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE, &extItem);
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ oidSeq = CERT_DecodeOidSequence(&extItem);
+ if ( oidSeq == NULL ) {
+ goto loser;
+ }
+
+ oids = oidSeq->oids;
+ while ( oids != NULL && *oids != NULL ) {
+ oid = *oids;
+
+ oidTag = SECOID_FindOIDTag(oid);
+
+ if ( oidTag == SEC_OID_NS_KEY_USAGE_GOVT_APPROVED ) {
+ goto success;
+ }
+
+ oids++;
+ }
+
+loser:
+ ret = PR_FALSE;
+ goto done;
+success:
+ ret = PR_TRUE;
+done:
+ if ( oidSeq != NULL ) {
+ CERT_DestroyOidSequence(oidSeq);
+ }
+ if (extItem.data != NULL) {
+ PORT_Free(extItem.data);
+ }
+ return(ret);
+}
diff --git a/security/nss/lib/certdb/secname.c b/security/nss/lib/certdb/secname.c
new file mode 100644
index 000000000..a508dcb44
--- /dev/null
+++ b/security/nss/lib/certdb/secname.c
@@ -0,0 +1,653 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+#include "cert.h"
+#include "secoid.h"
+#include "secder.h" /* XXX remove this when remove the DERTemplates */
+#include "secasn1.h"
+#include "secitem.h"
+#include <stdarg.h>
+#include "secerr.h"
+
+static const SEC_ASN1Template cert_AVATemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTAVA) },
+ { SEC_ASN1_OBJECT_ID,
+ offsetof(CERTAVA,type), },
+ { SEC_ASN1_ANY,
+ offsetof(CERTAVA,value), },
+ { 0, }
+};
+
+const SEC_ASN1Template CERT_RDNTemplate[] = {
+ { SEC_ASN1_SET_OF,
+ offsetof(CERTRDN,avas), cert_AVATemplate, sizeof(CERTRDN) }
+};
+
+
+static int
+CountArray(void **array)
+{
+ int count = 0;
+ if (array) {
+ while (*array++) {
+ count++;
+ }
+ }
+ return count;
+}
+
+static void
+**AddToArray(PRArenaPool *arena, void **array, void *element)
+{
+ unsigned count;
+ void **ap;
+
+ /* Count up number of slots already in use in the array */
+ count = 0;
+ ap = array;
+ if (ap) {
+ while (*ap++) {
+ count++;
+ }
+ }
+
+ if (array) {
+ array = (void**) PORT_ArenaGrow(arena, array,
+ (count + 1) * sizeof(void *),
+ (count + 2) * sizeof(void *));
+ } else {
+ array = (void**) PORT_ArenaAlloc(arena, (count + 2) * sizeof(void *));
+ }
+ if (array) {
+ array[count] = element;
+ array[count+1] = 0;
+ }
+ return array;
+}
+
+#if 0
+static void
+**RemoveFromArray(void **array, void *element)
+{
+ unsigned count;
+ void **ap;
+ int slot;
+
+ /* Look for element */
+ ap = array;
+ if (ap) {
+ count = 1; /* count the null at the end */
+ slot = -1;
+ for (; *ap; ap++, count++) {
+ if (*ap == element) {
+ /* Found it */
+ slot = ap - array;
+ }
+ }
+ if (slot >= 0) {
+ /* Found it. Squish array down */
+ PORT_Memmove((void*) (array + slot), (void*) (array + slot + 1),
+ (count - slot - 1) * sizeof(void*));
+ /* Don't bother reallocing the memory */
+ }
+ }
+ return array;
+}
+#endif /* 0 */
+
+SECOidTag
+CERT_GetAVATag(CERTAVA *ava)
+{
+ SECOidData *oid;
+ if (!ava->type.data) return (SECOidTag)-1;
+
+ oid = SECOID_FindOID(&ava->type);
+
+ if ( oid ) {
+ return(oid->offset);
+ }
+ return (SECOidTag)-1;
+}
+
+static SECStatus
+SetupAVAType(PRArenaPool *arena, SECOidTag type, SECItem *it, unsigned *maxLenp)
+{
+ unsigned char *oid;
+ unsigned oidLen;
+ unsigned char *cp;
+ unsigned maxLen;
+ SECOidData *oidrec;
+
+ oidrec = SECOID_FindOIDByTag(type);
+ if (oidrec == NULL)
+ return SECFailure;
+
+ oid = oidrec->oid.data;
+ oidLen = oidrec->oid.len;
+
+ switch (type) {
+ case SEC_OID_AVA_COUNTRY_NAME:
+ maxLen = 2;
+ break;
+ case SEC_OID_AVA_ORGANIZATION_NAME:
+ maxLen = 64;
+ break;
+ case SEC_OID_AVA_COMMON_NAME:
+ maxLen = 64;
+ break;
+ case SEC_OID_AVA_LOCALITY:
+ maxLen = 128;
+ break;
+ case SEC_OID_AVA_STATE_OR_PROVINCE:
+ maxLen = 128;
+ break;
+ case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME:
+ maxLen = 64;
+ break;
+ case SEC_OID_AVA_DC:
+ maxLen = 128;
+ break;
+ case SEC_OID_AVA_DN_QUALIFIER:
+ maxLen = 0x7fff;
+ break;
+ case SEC_OID_PKCS9_EMAIL_ADDRESS:
+ maxLen = 128;
+ break;
+ case SEC_OID_RFC1274_UID:
+ maxLen = 256; /* RFC 1274 specifies 256 */
+ break;
+ case SEC_OID_RFC1274_MAIL:
+ maxLen = 256; /* RFC 1274 specifies 256 */
+ break;
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ it->data = cp = (unsigned char*) PORT_ArenaAlloc(arena, oidLen);
+ if (cp == NULL) {
+ return SECFailure;
+ }
+ it->len = oidLen;
+ PORT_Memcpy(cp, oid, oidLen);
+ *maxLenp = maxLen;
+ return SECSuccess;
+}
+
+static SECStatus
+SetupAVAValue(PRArenaPool *arena, int valueType, char *value, SECItem *it,
+ unsigned maxLen)
+{
+ unsigned valueLen, valueLenLen, total;
+ unsigned ucs4Len = 0, ucs4MaxLen;
+ unsigned char *cp, *ucs4Val;
+
+ switch (valueType) {
+ case SEC_ASN1_PRINTABLE_STRING:
+ case SEC_ASN1_IA5_STRING:
+ case SEC_ASN1_T61_STRING:
+ valueLen = PORT_Strlen(value);
+ break;
+ case SEC_ASN1_UNIVERSAL_STRING:
+ valueLen = PORT_Strlen(value);
+ ucs4Val = (unsigned char *)PORT_ArenaZAlloc(arena,
+ PORT_Strlen(value) * 6);
+ ucs4MaxLen = PORT_Strlen(value) * 6;
+ if(!ucs4Val || !PORT_UCS4_UTF8Conversion(PR_TRUE, (unsigned char *)value, valueLen,
+ ucs4Val, ucs4MaxLen, &ucs4Len)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ value = (char *)ucs4Val;
+ valueLen = ucs4Len;
+ break;
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (((valueType != SEC_ASN1_UNIVERSAL_STRING) && (valueLen > maxLen)) ||
+ ((valueType == SEC_ASN1_UNIVERSAL_STRING) && (valueLen > (maxLen * 4)))) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ valueLenLen = DER_LengthLength(valueLen);
+ total = 1 + valueLenLen + valueLen;
+ it->data = cp = (unsigned char*) PORT_ArenaAlloc(arena, total);
+ if (!cp) {
+ return SECFailure;
+ }
+ it->len = total;
+ cp = (unsigned char*) DER_StoreHeader(cp, valueType, valueLen);
+ PORT_Memcpy(cp, value, valueLen);
+ return SECSuccess;
+}
+
+CERTAVA *
+CERT_CreateAVA(PRArenaPool *arena, SECOidTag kind, int valueType, char *value)
+{
+ CERTAVA *ava;
+ int rv;
+ unsigned maxLen;
+
+ ava = (CERTAVA*) PORT_ArenaZAlloc(arena, sizeof(CERTAVA));
+ if (ava) {
+ rv = SetupAVAType(arena, kind, &ava->type, &maxLen);
+ if (rv) {
+ /* Illegal AVA type */
+ return 0;
+ }
+ rv = SetupAVAValue(arena, valueType, value, &ava->value, maxLen);
+ if (rv) {
+ /* Illegal value type */
+ return 0;
+ }
+ }
+ return ava;
+}
+
+CERTAVA *
+CERT_CopyAVA(PRArenaPool *arena, CERTAVA *from)
+{
+ CERTAVA *ava;
+ int rv;
+
+ ava = (CERTAVA*) PORT_ArenaZAlloc(arena, sizeof(CERTAVA));
+ if (ava) {
+ rv = SECITEM_CopyItem(arena, &ava->type, &from->type);
+ if (rv) goto loser;
+ rv = SECITEM_CopyItem(arena, &ava->value, &from->value);
+ if (rv) goto loser;
+ }
+ return ava;
+
+ loser:
+ return 0;
+}
+
+/************************************************************************/
+/* XXX This template needs to go away in favor of the new SEC_ASN1 version. */
+static const SEC_ASN1Template cert_RDNTemplate[] = {
+ { SEC_ASN1_SET_OF,
+ offsetof(CERTRDN,avas), cert_AVATemplate, sizeof(CERTRDN) }
+};
+
+
+CERTRDN *
+CERT_CreateRDN(PRArenaPool *arena, CERTAVA *ava0, ...)
+{
+ CERTAVA *ava;
+ CERTRDN *rdn;
+ va_list ap;
+ unsigned count;
+ CERTAVA **avap;
+
+ rdn = (CERTRDN*) PORT_ArenaAlloc(arena, sizeof(CERTRDN));
+ if (rdn) {
+ /* Count number of avas going into the rdn */
+ count = 0;
+ if (ava0) {
+ count++;
+ va_start(ap, ava0);
+ while ((ava = va_arg(ap, CERTAVA*)) != 0) {
+ count++;
+ }
+ va_end(ap);
+ }
+
+ /* Now fill in the pointers */
+ rdn->avas = avap =
+ (CERTAVA**) PORT_ArenaAlloc( arena, (count + 1)*sizeof(CERTAVA*));
+ if (!avap) {
+ return 0;
+ }
+ if (ava0) {
+ *avap++ = ava0;
+ va_start(ap, ava0);
+ while ((ava = va_arg(ap, CERTAVA*)) != 0) {
+ *avap++ = ava;
+ }
+ va_end(ap);
+ }
+ *avap++ = 0;
+ }
+ return rdn;
+}
+
+SECStatus
+CERT_AddAVA(PRArenaPool *arena, CERTRDN *rdn, CERTAVA *ava)
+{
+ rdn->avas = (CERTAVA**) AddToArray(arena, (void**) rdn->avas, ava);
+ return rdn->avas ? SECSuccess : SECFailure;
+}
+
+SECStatus
+CERT_CopyRDN(PRArenaPool *arena, CERTRDN *to, CERTRDN *from)
+{
+ CERTAVA **avas, *fava, *tava;
+ SECStatus rv;
+
+ /* Copy each ava from from */
+ avas = from->avas;
+ while ((fava = *avas++) != 0) {
+ tava = CERT_CopyAVA(arena, fava);
+ if (!tava) return SECFailure;
+ rv = CERT_AddAVA(arena, to, tava);
+ if (rv) return rv;
+ }
+ return SECSuccess;
+}
+
+/************************************************************************/
+
+const SEC_ASN1Template CERT_NameTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF,
+ offsetof(CERTName,rdns), CERT_RDNTemplate, sizeof(CERTName) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(CERT_NameTemplate)
+
+CERTName *
+CERT_CreateName(CERTRDN *rdn0, ...)
+{
+ CERTRDN *rdn;
+ CERTName *name;
+ va_list ap;
+ unsigned count;
+ CERTRDN **rdnp;
+ PRArenaPool *arena;
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if ( !arena ) {
+ return(0);
+ }
+
+ name = (CERTName*) PORT_ArenaAlloc(arena, sizeof(CERTName));
+ if (name) {
+ name->arena = arena;
+
+ /* Count number of RDNs going into the Name */
+ if (!rdn0) {
+ count = 0;
+ } else {
+ count = 1;
+ va_start(ap, rdn0);
+ while ((rdn = va_arg(ap, CERTRDN*)) != 0) {
+ count++;
+ }
+ va_end(ap);
+ }
+
+ /* Allocate space (including space for terminal null ptr) */
+ name->rdns = rdnp =
+ (CERTRDN**) PORT_ArenaAlloc(arena, (count + 1) * sizeof(CERTRDN*));
+ if (!name->rdns) {
+ goto loser;
+ }
+
+ /* Now fill in the pointers */
+ if (count > 0) {
+ *rdnp++ = rdn0;
+ va_start(ap, rdn0);
+ while ((rdn = va_arg(ap, CERTRDN*)) != 0) {
+ *rdnp++ = rdn;
+ }
+ va_end(ap);
+ }
+
+ /* null terminate the list */
+ *rdnp++ = 0;
+ }
+ return name;
+
+loser:
+ PORT_FreeArena(arena, PR_FALSE);
+ return(0);
+}
+
+void
+CERT_DestroyName(CERTName *name)
+{
+ if (name)
+ {
+ PRArenaPool *arena = name->arena;
+ name->rdns = NULL;
+ name->arena = NULL;
+ if (arena) PORT_FreeArena(arena, PR_FALSE);
+ }
+}
+
+SECStatus
+CERT_AddRDN(CERTName *name, CERTRDN *rdn)
+{
+ name->rdns = (CERTRDN**) AddToArray(name->arena, (void**) name->rdns, rdn);
+ return name->rdns ? SECSuccess : SECFailure;
+}
+
+SECStatus
+CERT_CopyName(PRArenaPool *arena, CERTName *to, CERTName *from)
+{
+ CERTRDN **rdns, *frdn, *trdn;
+ SECStatus rv;
+
+ if (!to || !from)
+ return SECFailure;
+
+ CERT_DestroyName(to);
+ to->arena = arena;
+
+ /* Copy each rdn from from */
+ rdns = from->rdns;
+ while ((frdn = *rdns++) != 0) {
+ trdn = CERT_CreateRDN(arena, 0);
+ if ( trdn == NULL ) {
+ return(SECFailure);
+ }
+ rv = CERT_CopyRDN(arena, trdn, frdn);
+ if (rv) return rv;
+ rv = CERT_AddRDN(to, trdn);
+ if (rv) return rv;
+ }
+ return SECSuccess;
+}
+
+/************************************************************************/
+
+SECComparison
+CERT_CompareAVA(CERTAVA *a, CERTAVA *b)
+{
+ SECComparison rv;
+
+ rv = SECITEM_CompareItem(&a->type, &b->type);
+ if (rv) {
+ /*
+ ** XXX for now we are going to just assume that a bitwise
+ ** comparison of the value codes will do the trick.
+ */
+ }
+ rv = SECITEM_CompareItem(&a->value, &b->value);
+ return rv;
+}
+
+SECComparison
+CERT_CompareRDN(CERTRDN *a, CERTRDN *b)
+{
+ CERTAVA **aavas, *aava;
+ CERTAVA **bavas, *bava;
+ int ac, bc;
+ SECComparison rv = SECEqual;
+
+ aavas = a->avas;
+ bavas = b->avas;
+
+ /*
+ ** Make sure array of ava's are the same length. If not, then we are
+ ** not equal
+ */
+ ac = CountArray((void**) aavas);
+ bc = CountArray((void**) bavas);
+ if (ac < bc) return SECLessThan;
+ if (ac > bc) return SECGreaterThan;
+
+ for (;;) {
+ aava = *aavas++;
+ bava = *bavas++;
+ if (!aava) {
+ break;
+ }
+ rv = CERT_CompareAVA(aava, bava);
+ if (rv) return rv;
+ }
+ return rv;
+}
+
+SECComparison
+CERT_CompareName(CERTName *a, CERTName *b)
+{
+ CERTRDN **ardns, *ardn;
+ CERTRDN **brdns, *brdn;
+ int ac, bc;
+ SECComparison rv = SECEqual;
+
+ ardns = a->rdns;
+ brdns = b->rdns;
+
+ /*
+ ** Make sure array of rdn's are the same length. If not, then we are
+ ** not equal
+ */
+ ac = CountArray((void**) ardns);
+ bc = CountArray((void**) brdns);
+ if (ac < bc) return SECLessThan;
+ if (ac > bc) return SECGreaterThan;
+
+ for (;;) {
+ ardn = *ardns++;
+ brdn = *brdns++;
+ if (!ardn) {
+ break;
+ }
+ rv = CERT_CompareRDN(ardn, brdn);
+ if (rv) return rv;
+ }
+ return rv;
+}
+
+/* Moved from certhtml.c */
+SECItem *
+CERT_DecodeAVAValue(SECItem *derAVAValue)
+{
+ SECItem *retItem;
+ const SEC_ASN1Template *theTemplate = NULL;
+ PRBool convertUCS4toUTF8 = PR_FALSE;
+ PRBool convertUCS2toUTF8 = PR_FALSE;
+ SECItem avaValue = {siBuffer, 0};
+ PLArenaPool *newarena = NULL;
+
+ if(!derAVAValue) {
+ return NULL;
+ }
+
+ switch(derAVAValue->data[0]) {
+ case SEC_ASN1_UNIVERSAL_STRING:
+ convertUCS4toUTF8 = PR_TRUE;
+ theTemplate = SEC_UniversalStringTemplate;
+ break;
+ case SEC_ASN1_IA5_STRING:
+ theTemplate = SEC_IA5StringTemplate;
+ break;
+ case SEC_ASN1_PRINTABLE_STRING:
+ theTemplate = SEC_PrintableStringTemplate;
+ break;
+ case SEC_ASN1_T61_STRING:
+ theTemplate = SEC_T61StringTemplate;
+ break;
+ case SEC_ASN1_BMP_STRING:
+ convertUCS2toUTF8 = PR_TRUE;
+ theTemplate = SEC_BMPStringTemplate;
+ break;
+ case SEC_ASN1_UTF8_STRING:
+ /* No conversion needed ! */
+ theTemplate = SEC_UTF8StringTemplate;
+ break;
+ default:
+ return NULL;
+ }
+
+ PORT_Memset(&avaValue, 0, sizeof(SECItem));
+ newarena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (!newarena) {
+ return NULL;
+ }
+ if(SEC_QuickDERDecodeItem(newarena, &avaValue, theTemplate, derAVAValue)
+ != SECSuccess) {
+ PORT_FreeArena(newarena, PR_FALSE);
+ return NULL;
+ }
+
+ if (convertUCS4toUTF8) {
+ unsigned int utf8ValLen = avaValue.len * 3;
+ unsigned char *utf8Val = (unsigned char*)
+ PORT_ArenaZAlloc(newarena, utf8ValLen);
+
+ if(!PORT_UCS4_UTF8Conversion(PR_FALSE, avaValue.data, avaValue.len,
+ utf8Val, utf8ValLen, &utf8ValLen)) {
+ PORT_FreeArena(newarena, PR_FALSE);
+ return NULL;
+ }
+
+ avaValue.data = utf8Val;
+ avaValue.len = utf8ValLen;
+
+ } else if (convertUCS2toUTF8) {
+
+ unsigned int utf8ValLen = avaValue.len * 3;
+ unsigned char *utf8Val = (unsigned char*)
+ PORT_ArenaZAlloc(newarena, utf8ValLen);
+
+ if(!PORT_UCS2_UTF8Conversion(PR_FALSE, avaValue.data, avaValue.len,
+ utf8Val, utf8ValLen, &utf8ValLen)) {
+ PORT_FreeArena(newarena, PR_FALSE);
+ return NULL;
+ }
+
+ avaValue.data = utf8Val;
+ avaValue.len = utf8ValLen;
+ }
+
+ retItem = SECITEM_DupItem(&avaValue);
+ PORT_FreeArena(newarena, PR_FALSE);
+ return retItem;
+}
diff --git a/security/nss/lib/certdb/stanpcertdb.c b/security/nss/lib/certdb/stanpcertdb.c
new file mode 100644
index 000000000..bd905e5fb
--- /dev/null
+++ b/security/nss/lib/certdb/stanpcertdb.c
@@ -0,0 +1,978 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+#include "prtime.h"
+
+#include "cert.h"
+#include "mcom_db.h"
+#include "certdb.h"
+#include "secitem.h"
+#include "secder.h"
+
+/* Call to PK11_FreeSlot below */
+
+#include "secasn1.h"
+#include "secerr.h"
+#include "nssilock.h"
+#include "prmon.h"
+#include "nsslocks.h"
+#include "base64.h"
+#include "sechash.h"
+#include "plhash.h"
+#include "pk11func.h" /* sigh */
+
+#ifndef NSS_3_4_CODE
+#define NSS_3_4_CODE
+#endif /* NSS_3_4_CODE */
+#include "nsspki.h"
+#include "pki.h"
+#include "pkim.h"
+#include "pki3hack.h"
+#include "ckhelper.h"
+#include "base.h"
+#include "pkistore.h"
+#include "dev3hack.h"
+#include "dev.h"
+
+PRBool
+SEC_CertNicknameConflict(char *nickname, SECItem *derSubject,
+ CERTCertDBHandle *handle)
+{
+ CERTCertificate *cert;
+ PRBool conflict = PR_FALSE;
+
+ cert=CERT_FindCertByNickname(handle, nickname);
+
+ if (!cert) {
+ return conflict;
+ }
+
+ conflict = !SECITEM_ItemsAreEqual(derSubject,&cert->derSubject);
+ CERT_DestroyCertificate(cert);
+ return conflict;
+}
+
+SECStatus
+SEC_DeletePermCertificate(CERTCertificate *cert)
+{
+ PRStatus nssrv;
+ NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
+ NSSCertificate *c = STAN_GetNSSCertificate(cert);
+
+ /* get rid of the token instances */
+ nssrv = NSSCertificate_DeleteStoredObject(c, NULL);
+
+ /* get rid of the cache entry */
+ nssTrustDomain_LockCertCache(td);
+ nssTrustDomain_RemoveCertFromCacheLOCKED(td, c);
+ nssTrustDomain_UnlockCertCache(td);
+
+ return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
+}
+
+SECStatus
+CERT_GetCertTrust(CERTCertificate *cert, CERTCertTrust *trust)
+{
+ SECStatus rv;
+ CERT_LockCertTrust(cert);
+ if ( cert->trust == NULL ) {
+ rv = SECFailure;
+ } else {
+ *trust = *cert->trust;
+ rv = SECSuccess;
+ }
+ CERT_UnlockCertTrust(cert);
+ return(rv);
+}
+
+#ifdef notdef
+static char *
+cert_parseNickname(char *nickname)
+{
+ char *cp;
+ for (cp=nickname; *cp && *cp != ':'; cp++);
+ if (*cp == ':') return cp+1;
+ return nickname;
+}
+#endif
+
+SECStatus
+CERT_ChangeCertTrust(CERTCertDBHandle *handle, CERTCertificate *cert,
+ CERTCertTrust *trust)
+{
+ SECStatus rv = SECFailure;
+ PRStatus ret;
+
+ CERT_LockCertTrust(cert);
+ ret = STAN_ChangeCertTrust(cert, trust);
+ rv = (ret == PR_SUCCESS) ? SECSuccess : SECFailure;
+ CERT_UnlockCertTrust(cert);
+ return rv;
+}
+
+extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
+
+SECStatus
+__CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname,
+ CERTCertTrust *trust)
+{
+ NSSUTF8 *stanNick;
+ PK11SlotInfo *slot;
+ NSSToken *internal;
+ NSSCryptoContext *context;
+ nssCryptokiObject *permInstance;
+ NSSCertificate *c = STAN_GetNSSCertificate(cert);
+ context = c->object.cryptoContext;
+ if (!context) {
+ return SECFailure; /* wasn't a temp cert */
+ }
+ stanNick = nssCertificate_GetNickname(c, NULL);
+ if (stanNick && nickname && strcmp(nickname, stanNick) != 0) {
+ /* take the new nickname */
+ cert->nickname = NULL;
+ stanNick = NULL;
+ }
+ if (!stanNick && nickname) {
+ stanNick = nssUTF8_Duplicate((NSSUTF8 *)nickname, c->object.arena);
+ }
+ /* Delete the temp instance */
+ nssCertificateStore_Lock(context->certStore);
+ nssCertificateStore_RemoveCertLOCKED(context->certStore, c);
+ nssCertificateStore_Unlock(context->certStore);
+ c->object.cryptoContext = NULL;
+ /* Import the perm instance onto the internal token */
+ slot = PK11_GetInternalKeySlot();
+ internal = PK11Slot_GetNSSToken(slot);
+ permInstance = nssToken_ImportCertificate(internal, NULL,
+ NSSCertificateType_PKIX,
+ &c->id,
+ stanNick,
+ &c->encoding,
+ &c->issuer,
+ &c->subject,
+ &c->serial,
+ cert->emailAddr,
+ PR_TRUE);
+ PK11_FreeSlot(slot);
+ if (!permInstance) {
+ if (NSS_GetError() == NSS_ERROR_INVALID_CERTIFICATE) {
+ PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL);
+ }
+ return SECFailure;
+ }
+ nssPKIObject_AddInstance(&c->object, permInstance);
+ nssTrustDomain_AddCertsToCache(STAN_GetDefaultTrustDomain(), &c, 1);
+ /* reset the CERTCertificate fields */
+ cert->nssCertificate = NULL;
+ cert = STAN_GetCERTCertificate(c); /* will return same pointer */
+ if (!cert) {
+ return SECFailure;
+ }
+ cert->istemp = PR_FALSE;
+ cert->isperm = PR_TRUE;
+ if (!trust) {
+ return SECSuccess;
+ }
+ return (STAN_ChangeCertTrust(cert, trust) == PR_SUCCESS) ?
+ SECSuccess: SECFailure;
+}
+
+SECStatus
+CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname,
+ CERTCertTrust *trust)
+{
+ return __CERT_AddTempCertToPerm(cert, nickname, trust);
+}
+
+CERTCertificate *
+__CERT_NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert,
+ char *nickname, PRBool isperm, PRBool copyDER)
+{
+ PRStatus nssrv;
+ NSSCertificate *c;
+ CERTCertificate *cc;
+ NSSCertificate *tempCert;
+ nssPKIObject *pkio;
+ NSSCryptoContext *gCC = STAN_GetDefaultCryptoContext();
+ NSSTrustDomain *gTD = STAN_GetDefaultTrustDomain();
+ if (!isperm) {
+ NSSDER encoding;
+ NSSITEM_FROM_SECITEM(&encoding, derCert);
+ /* First, see if it is already a temp cert */
+ c = NSSCryptoContext_FindCertificateByEncodedCertificate(gCC,
+ &encoding);
+ if (!c) {
+ /* Then, see if it is already a perm cert */
+ c = NSSTrustDomain_FindCertificateByEncodedCertificate(handle,
+ &encoding);
+ /* actually, that search ends up going by issuer/serial,
+ * so it is still possible to return a cert with the same
+ * issuer/serial but a different encoding, and we're
+ * going to reject that
+ */
+ if (c && !nssItem_Equal(&c->encoding, &encoding, NULL)) {
+ nssCertificate_Destroy(c);
+ PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL);
+ return NULL;
+ }
+ }
+ if (c) {
+ return STAN_GetCERTCertificate(c);
+ }
+ }
+ pkio = nssPKIObject_Create(NULL, NULL, gTD, gCC);
+ if (!pkio) {
+ return NULL;
+ }
+ c = nss_ZNEW(pkio->arena, NSSCertificate);
+ if (!c) {
+ nssPKIObject_Destroy(pkio);
+ return NULL;
+ }
+ c->object = *pkio;
+ if (copyDER) {
+ nssItem_Create(c->object.arena, &c->encoding,
+ derCert->len, derCert->data);
+ } else {
+ NSSITEM_FROM_SECITEM(&c->encoding, derCert);
+ }
+ /* Forces a decoding of the cert in order to obtain the parts used
+ * below
+ */
+ cc = STAN_GetCERTCertificate(c);
+ if (!cc) {
+ return NULL;
+ }
+ nssItem_Create(c->object.arena,
+ &c->issuer, cc->derIssuer.len, cc->derIssuer.data);
+ nssItem_Create(c->object.arena,
+ &c->subject, cc->derSubject.len, cc->derSubject.data);
+ if (PR_TRUE) {
+ /* CERTCertificate stores serial numbers decoded. I need the DER
+ * here. sigh.
+ */
+ SECItem derSerial = { 0 };
+ CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial);
+ if (!derSerial.data) goto loser;
+ nssItem_Create(c->object.arena, &c->serial, derSerial.len, derSerial.data);
+ PORT_Free(derSerial.data);
+ }
+ if (nickname) {
+ c->object.tempName = nssUTF8_Create(c->object.arena,
+ nssStringType_UTF8String,
+ (NSSUTF8 *)nickname,
+ PORT_Strlen(nickname));
+ }
+ if (cc->emailAddr) {
+ c->email = nssUTF8_Create(c->object.arena,
+ nssStringType_PrintableString,
+ (NSSUTF8 *)cc->emailAddr,
+ PORT_Strlen(cc->emailAddr));
+ }
+ /* this function cannot detect if the cert exists as a temp cert now, but
+ * didn't when CERT_NewTemp was first called.
+ */
+ nssrv = NSSCryptoContext_ImportCertificate(gCC, c);
+ if (nssrv != PR_SUCCESS) {
+ goto loser;
+ }
+ /* so find the entry in the temp store */
+ tempCert = NSSCryptoContext_FindCertificateByIssuerAndSerialNumber(gCC,
+ &c->issuer,
+ &c->serial);
+ /* destroy the copy */
+ NSSCertificate_Destroy(c);
+ if (tempCert) {
+ /* and use the "official" entry */
+ c = tempCert;
+ cc = STAN_GetCERTCertificate(c);
+ if (!cc) {
+ return NULL;
+ }
+ } else {
+ return NULL;
+ }
+ cc->istemp = PR_TRUE;
+ cc->isperm = PR_FALSE;
+ return cc;
+loser:
+ nssPKIObject_Destroy(&c->object);
+ return NULL;
+}
+
+CERTCertificate *
+CERT_NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert,
+ char *nickname, PRBool isperm, PRBool copyDER)
+{
+ return( __CERT_NewTempCertificate(handle, derCert, nickname,
+ isperm, copyDER) );
+}
+
+/* maybe all the wincx's should be some const for internal token login? */
+CERTCertificate *
+CERT_FindCertByIssuerAndSN(CERTCertDBHandle *handle, CERTIssuerAndSN *issuerAndSN)
+{
+ PK11SlotInfo *slot;
+ CERTCertificate *cert;
+
+ cert = PK11_FindCertByIssuerAndSN(&slot,issuerAndSN,NULL);
+ if (cert && slot) {
+ PK11_FreeSlot(slot);
+ }
+
+ return cert;
+}
+
+static NSSCertificate *
+get_best_temp_or_perm(NSSCertificate *ct, NSSCertificate *cp)
+{
+ NSSUsage usage;
+ NSSCertificate *arr[3];
+ if (!ct) {
+ return nssCertificate_AddRef(cp);
+ } else if (!cp) {
+ return nssCertificate_AddRef(ct);
+ }
+ arr[0] = ct;
+ arr[1] = cp;
+ arr[2] = NULL;
+ usage.anyUsage = PR_TRUE;
+ return nssCertificateArray_FindBestCertificate(arr, NULL, &usage, NULL);
+}
+
+CERTCertificate *
+CERT_FindCertByName(CERTCertDBHandle *handle, SECItem *name)
+{
+ NSSCertificate *cp, *ct, *c;
+ NSSDER subject;
+ NSSUsage usage;
+ NSSCryptoContext *cc;
+ NSSITEM_FROM_SECITEM(&subject, name);
+ usage.anyUsage = PR_TRUE;
+ cc = STAN_GetDefaultCryptoContext();
+ ct = NSSCryptoContext_FindBestCertificateBySubject(cc, &subject,
+ NULL, &usage, NULL);
+ cp = NSSTrustDomain_FindBestCertificateBySubject(handle, &subject,
+ NULL, &usage, NULL);
+ c = get_best_temp_or_perm(ct, cp);
+ if (ct) {
+ CERTCertificate *cert = STAN_GetCERTCertificate(ct);
+ if (!cert) {
+ return NULL;
+ }
+ CERT_DestroyCertificate(cert);
+ }
+ if (cp) {
+ CERTCertificate *cert = STAN_GetCERTCertificate(cp);
+ if (!cert) {
+ return NULL;
+ }
+ CERT_DestroyCertificate(cert);
+ }
+ if (c) {
+ return STAN_GetCERTCertificate(c);
+ } else {
+ return NULL;
+ }
+}
+
+CERTCertificate *
+CERT_FindCertByKeyID(CERTCertDBHandle *handle, SECItem *name, SECItem *keyID)
+{
+ CERTCertList *list =
+ CERT_CreateSubjectCertList(NULL,handle,name,0,PR_FALSE);
+ CERTCertificate *cert = NULL;
+ CERTCertListNode *node = CERT_LIST_HEAD(list);
+
+ if (list == NULL) return NULL;
+
+ for (node = CERT_LIST_HEAD(list); node ; node = CERT_LIST_NEXT(node)) {
+ if (SECITEM_ItemsAreEqual(&cert->subjectKeyID, keyID) ) {
+ cert = CERT_DupCertificate(node->cert);
+ break;
+ }
+ }
+ return cert;
+}
+
+CERTCertificate *
+CERT_FindCertByNickname(CERTCertDBHandle *handle, char *nickname)
+{
+ NSSCryptoContext *cc;
+ NSSCertificate *c, *ct;
+ CERTCertificate *cert;
+ NSSUsage usage;
+ usage.anyUsage = PR_TRUE;
+ cc = STAN_GetDefaultCryptoContext();
+ ct = NSSCryptoContext_FindBestCertificateByNickname(cc, nickname,
+ NULL, &usage, NULL);
+ cert = PK11_FindCertFromNickname(nickname, NULL);
+ c = NULL;
+ if (cert) {
+ c = get_best_temp_or_perm(ct, STAN_GetNSSCertificate(cert));
+ CERT_DestroyCertificate(cert);
+ if (ct) {
+ CERTCertificate *cert2 = STAN_GetCERTCertificate(ct);
+ if (!cert2) {
+ return NULL;
+ }
+ CERT_DestroyCertificate(cert2);
+ }
+ } else {
+ c = ct;
+ }
+ if (c) {
+ return STAN_GetCERTCertificate(c);
+ } else {
+ return NULL;
+ }
+}
+
+CERTCertificate *
+CERT_FindCertByDERCert(CERTCertDBHandle *handle, SECItem *derCert)
+{
+ NSSCryptoContext *cc;
+ NSSCertificate *c;
+ NSSDER encoding;
+ NSSITEM_FROM_SECITEM(&encoding, derCert);
+ cc = STAN_GetDefaultCryptoContext();
+ c = NSSCryptoContext_FindCertificateByEncodedCertificate(cc, &encoding);
+ if (!c) {
+ c = NSSTrustDomain_FindCertificateByEncodedCertificate(handle,
+ &encoding);
+ if (!c) return NULL;
+ }
+ return STAN_GetCERTCertificate(c);
+}
+
+CERTCertificate *
+CERT_FindCertByNicknameOrEmailAddr(CERTCertDBHandle *handle, char *name)
+{
+ NSSCryptoContext *cc;
+ NSSCertificate *c, *ct;
+ CERTCertificate *cert;
+ NSSUsage usage;
+ usage.anyUsage = PR_TRUE;
+ cc = STAN_GetDefaultCryptoContext();
+ ct = NSSCryptoContext_FindBestCertificateByNickname(cc, name,
+ NULL, &usage, NULL);
+ if (!ct) {
+ ct = NSSCryptoContext_FindBestCertificateByEmail(cc, name,
+ NULL, &usage, NULL);
+ }
+ cert = PK11_FindCertFromNickname(name, NULL);
+ if (cert) {
+ c = get_best_temp_or_perm(ct, STAN_GetNSSCertificate(cert));
+ CERT_DestroyCertificate(cert);
+ if (ct) {
+ CERTCertificate *cert2 = STAN_GetCERTCertificate(ct);
+ if (!cert2) {
+ return NULL;
+ }
+ CERT_DestroyCertificate(cert2);
+ }
+ } else {
+ c = ct;
+ }
+ if (c) {
+ return STAN_GetCERTCertificate(c);
+ }
+ return NULL;
+}
+
+static void
+add_to_subject_list(CERTCertList *certList, CERTCertificate *cert,
+ PRBool validOnly, int64 sorttime)
+{
+ SECStatus secrv;
+ if (!validOnly ||
+ CERT_CheckCertValidTimes(cert, sorttime, PR_FALSE)
+ == secCertTimeValid) {
+ secrv = CERT_AddCertToListSorted(certList, cert,
+ CERT_SortCBValidity,
+ (void *)&sorttime);
+ if (secrv != SECSuccess) {
+ CERT_DestroyCertificate(cert);
+ }
+ } else {
+ CERT_DestroyCertificate(cert);
+ }
+}
+
+CERTCertList *
+CERT_CreateSubjectCertList(CERTCertList *certList, CERTCertDBHandle *handle,
+ SECItem *name, int64 sorttime, PRBool validOnly)
+{
+ NSSCryptoContext *cc;
+ NSSCertificate **tSubjectCerts, **pSubjectCerts;
+ NSSCertificate **ci;
+ CERTCertificate *cert;
+ NSSDER subject;
+ PRBool myList = PR_FALSE;
+ cc = STAN_GetDefaultCryptoContext();
+ NSSITEM_FROM_SECITEM(&subject, name);
+ /* Collect both temp and perm certs for the subject */
+ tSubjectCerts = NSSCryptoContext_FindCertificatesBySubject(cc,
+ &subject,
+ NULL,
+ 0,
+ NULL);
+ pSubjectCerts = NSSTrustDomain_FindCertificatesBySubject(handle,
+ &subject,
+ NULL,
+ 0,
+ NULL);
+ if (!tSubjectCerts && !pSubjectCerts) {
+ return NULL;
+ }
+ if (certList == NULL) {
+ certList = CERT_NewCertList();
+ myList = PR_TRUE;
+ if (!certList) goto loser;
+ }
+ /* Iterate over the matching temp certs. Add them to the list */
+ ci = tSubjectCerts;
+ while (ci && *ci) {
+ cert = STAN_GetCERTCertificate(*ci);
+ if (cert) {
+ add_to_subject_list(certList, cert, validOnly, sorttime);
+ }
+ ci++;
+ }
+ /* Iterate over the matching perm certs. Add them to the list */
+ ci = pSubjectCerts;
+ while (ci && *ci) {
+ cert = STAN_GetCERTCertificate(*ci);
+ if (cert) {
+ add_to_subject_list(certList, cert, validOnly, sorttime);
+ }
+ ci++;
+ }
+ nss_ZFreeIf(tSubjectCerts);
+ nss_ZFreeIf(pSubjectCerts);
+ return certList;
+loser:
+ nss_ZFreeIf(tSubjectCerts);
+ nss_ZFreeIf(pSubjectCerts);
+ if (myList && certList != NULL) {
+ CERT_DestroyCertList(certList);
+ }
+ return NULL;
+}
+
+void
+CERT_DestroyCertificate(CERTCertificate *cert)
+{
+ if ( cert ) {
+ /* don't use STAN_GetNSSCertificate because we don't want to
+ * go to the trouble of translating the CERTCertificate into
+ * an NSSCertificate just to destroy it. If it hasn't been done
+ * yet, don't do it at all.
+ */
+ NSSCertificate *tmp = cert->nssCertificate;
+ if (tmp) {
+ /* delete the NSSCertificate */
+ NSSCertificate_Destroy(tmp);
+ } else {
+ PORT_FreeArena(cert->arena, PR_FALSE);
+ }
+ }
+ return;
+}
+
+#ifdef notdef
+SECStatus
+CERT_ChangeCertTrustByUsage(CERTCertDBHandle *certdb,
+ CERTCertificate *cert, SECCertUsage usage)
+{
+ SECStatus rv;
+ CERTCertTrust trust;
+ CERTCertTrust tmptrust;
+ unsigned int certtype;
+ PRBool saveit;
+
+ saveit = PR_TRUE;
+
+ PORT_Memset((void *)&trust, 0, sizeof(trust));
+
+ certtype = cert->nsCertType;
+
+ /* if no app bits in cert type, then set all app bits */
+ if ( ! ( certtype & NS_CERT_TYPE_APP ) ) {
+ certtype |= NS_CERT_TYPE_APP;
+ }
+
+ switch ( usage ) {
+ case certUsageEmailSigner:
+ case certUsageEmailRecipient:
+ if ( certtype & NS_CERT_TYPE_EMAIL ) {
+ trust.emailFlags = CERTDB_VALID_PEER;
+ if ( ! ( cert->rawKeyUsage & KU_KEY_ENCIPHERMENT ) ) {
+ /* don't save it if KeyEncipherment is not allowed */
+ saveit = PR_FALSE;
+ }
+ }
+ break;
+ case certUsageUserCertImport:
+ if ( certtype & NS_CERT_TYPE_EMAIL ) {
+ trust.emailFlags = CERTDB_VALID_PEER;
+ }
+ /* VALID_USER is already set if the cert was imported,
+ * in the case that the cert was already in the database
+ * through SMIME or other means, we should set the USER
+ * flags, if they are not already set.
+ */
+ if( cert->isperm ) {
+ if ( certtype & NS_CERT_TYPE_SSL_CLIENT ) {
+ if( !(cert->trust->sslFlags & CERTDB_USER) ) {
+ trust.sslFlags |= CERTDB_USER;
+ }
+ }
+
+ if ( certtype & NS_CERT_TYPE_EMAIL ) {
+ if( !(cert->trust->emailFlags & CERTDB_USER) ) {
+ trust.emailFlags |= CERTDB_USER;
+ }
+ }
+
+ if ( certtype & NS_CERT_TYPE_OBJECT_SIGNING ) {
+ if( !(cert->trust->objectSigningFlags & CERTDB_USER) ) {
+ trust.objectSigningFlags |= CERTDB_USER;
+ }
+ }
+ }
+ break;
+ default: /* XXX added to quiet warnings; no other cases needed? */
+ break;
+ }
+
+ if ( (trust.sslFlags | trust.emailFlags | trust.objectSigningFlags) == 0 ){
+ saveit = PR_FALSE;
+ }
+
+ if ( saveit && cert->isperm ) {
+ /* Cert already in the DB. Just adjust flags */
+ tmptrust = *cert->trust;
+ tmptrust.sslFlags |= trust.sslFlags;
+ tmptrust.emailFlags |= trust.emailFlags;
+ tmptrust.objectSigningFlags |= trust.objectSigningFlags;
+
+ rv = CERT_ChangeCertTrust(cert->dbhandle, cert,
+ &tmptrust);
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+ }
+
+ rv = SECSuccess;
+ goto done;
+
+loser:
+ rv = SECFailure;
+done:
+
+ return(rv);
+}
+#endif
+
+int
+CERT_GetDBContentVersion(CERTCertDBHandle *handle)
+{
+ /* should read the DB content version from the pkcs #11 device */
+ return 0;
+}
+
+SECStatus
+certdb_SaveSingleProfile(CERTCertificate *cert, const char *emailAddr,
+ SECItem *emailProfile, SECItem *profileTime)
+{
+ int64 oldtime;
+ int64 newtime;
+ SECStatus rv = SECFailure;
+ PRBool saveit;
+ SECItem oldprof, oldproftime;
+ SECItem *oldProfile = NULL;
+ SECItem *oldProfileTime = NULL;
+ PK11SlotInfo *slot = NULL;
+ NSSCertificate *c;
+ NSSCryptoContext *cc;
+ nssSMIMEProfile *stanProfile = NULL;
+ PRBool freeOldProfile = PR_FALSE;
+
+ c = STAN_GetNSSCertificate(cert);
+ if (!c) return SECFailure;
+ cc = c->object.cryptoContext;
+ if (cc != NULL) {
+ stanProfile = nssCryptoContext_FindSMIMEProfileForCertificate(cc, c);
+ if (stanProfile) {
+ PORT_Assert(stanProfile->profileData);
+ SECITEM_FROM_NSSITEM(&oldprof, stanProfile->profileData);
+ oldProfile = &oldprof;
+ SECITEM_FROM_NSSITEM(&oldproftime, stanProfile->profileTime);
+ oldProfileTime = &oldproftime;
+ }
+ } else {
+ oldProfile = PK11_FindSMimeProfile(&slot, (char *)emailAddr,
+ &cert->derSubject, &oldProfileTime);
+ freeOldProfile = PR_TRUE;
+ }
+
+ saveit = PR_FALSE;
+
+ /* both profileTime and emailProfile have to exist or not exist */
+ if ( emailProfile == NULL ) {
+ profileTime = NULL;
+ } else if ( profileTime == NULL ) {
+ emailProfile = NULL;
+ }
+
+ if ( oldProfileTime == NULL ) {
+ saveit = PR_TRUE;
+ } else {
+ /* there was already a profile for this email addr */
+ if ( profileTime ) {
+ /* we have an old and new profile - save whichever is more recent*/
+ if ( oldProfileTime->len == 0 ) {
+ /* always replace if old entry doesn't have a time */
+ oldtime = LL_MININT;
+ } else {
+ rv = DER_UTCTimeToTime(&oldtime, oldProfileTime);
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+ }
+
+ rv = DER_UTCTimeToTime(&newtime, profileTime);
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ if ( LL_CMP(newtime, >, oldtime ) ) {
+ /* this is a newer profile, save it and cert */
+ saveit = PR_TRUE;
+ }
+ } else {
+ saveit = PR_TRUE;
+ }
+ }
+
+
+ if (saveit) {
+ if (cc) {
+ if (stanProfile) {
+ /* stanProfile is already stored in the crypto context,
+ * overwrite the data
+ */
+ NSSArena *arena = stanProfile->object.arena;
+ stanProfile->profileTime = nssItem_Create(arena,
+ NULL,
+ profileTime->len,
+ profileTime->data);
+ stanProfile->profileData = nssItem_Create(arena,
+ NULL,
+ emailProfile->len,
+ emailProfile->data);
+ } else if (profileTime && emailProfile) {
+ PRStatus nssrv;
+ NSSDER subject;
+ NSSItem profTime, profData;
+ NSSItem *pprofTime, *pprofData;
+ NSSITEM_FROM_SECITEM(&subject, &cert->derSubject);
+ if (profileTime) {
+ NSSITEM_FROM_SECITEM(&profTime, profileTime);
+ pprofTime = &profTime;
+ } else {
+ pprofTime = NULL;
+ }
+ if (emailProfile) {
+ NSSITEM_FROM_SECITEM(&profData, emailProfile);
+ pprofData = &profData;
+ } else {
+ pprofData = NULL;
+ }
+ stanProfile = nssSMIMEProfile_Create(c, pprofTime, pprofData);
+ if (!stanProfile) goto loser;
+ nssrv = nssCryptoContext_ImportSMIMEProfile(cc, stanProfile);
+ rv = (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
+ }
+ } else {
+ rv = PK11_SaveSMimeProfile(slot, (char *)emailAddr,
+ &cert->derSubject, emailProfile, profileTime);
+ }
+ } else {
+ rv = SECSuccess;
+ }
+
+loser:
+ if (oldProfile && freeOldProfile) {
+ SECITEM_FreeItem(oldProfile,PR_TRUE);
+ }
+ if (oldProfileTime && freeOldProfile) {
+ SECITEM_FreeItem(oldProfileTime,PR_TRUE);
+ }
+ if (stanProfile) {
+ nssSMIMEProfile_Destroy(stanProfile);
+ }
+ if (slot) {
+ PK11_FreeSlot(slot);
+ }
+
+ return(rv);
+}
+
+/*
+ *
+ * Manage S/MIME profiles
+ *
+ */
+
+SECStatus
+CERT_SaveSMimeProfile(CERTCertificate *cert, SECItem *emailProfile,
+ SECItem *profileTime)
+{
+ const char *emailAddr;
+ SECStatus rv;
+
+ if (!cert) {
+ return SECFailure;
+ }
+
+ if (cert->slot && !PK11_IsInternal(cert->slot)) {
+ /* this cert comes from an external source, we need to add it
+ to the cert db before creating an S/MIME profile */
+ PK11SlotInfo* internalslot = PK11_GetInternalKeySlot();
+ if (!internalslot) {
+ return SECFailure;
+ }
+ rv = PK11_ImportCert(internalslot, cert,
+ CK_INVALID_HANDLE, NULL, PR_FALSE);
+
+ PK11_FreeSlot(internalslot);
+ if (rv != SECSuccess ) {
+ return SECFailure;
+ }
+ }
+
+
+ for (emailAddr = CERT_GetFirstEmailAddress(cert); emailAddr != NULL;
+ emailAddr = CERT_GetNextEmailAddress(cert,emailAddr)) {
+ rv = certdb_SaveSingleProfile(cert,emailAddr,emailProfile,profileTime);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ }
+ return SECSuccess;
+
+}
+
+
+SECItem *
+CERT_FindSMimeProfile(CERTCertificate *cert)
+{
+ PK11SlotInfo *slot = NULL;
+ NSSCertificate *c;
+ NSSCryptoContext *cc;
+ SECItem *rvItem = NULL;
+
+ c = STAN_GetNSSCertificate(cert);
+ if (!c) return NULL;
+ cc = c->object.cryptoContext;
+ if (cc != NULL) {
+ nssSMIMEProfile *stanProfile;
+ stanProfile = nssCryptoContext_FindSMIMEProfileForCertificate(cc, c);
+ if (stanProfile) {
+ rvItem = SECITEM_AllocItem(NULL, NULL,
+ stanProfile->profileData->size);
+ if (rvItem) {
+ rvItem->data = stanProfile->profileData->data;
+ }
+ nssSMIMEProfile_Destroy(stanProfile);
+ }
+ return rvItem;
+ }
+ rvItem =
+ PK11_FindSMimeProfile(&slot, cert->emailAddr, &cert->derSubject, NULL);
+ if (slot) {
+ PK11_FreeSlot(slot);
+ }
+ return rvItem;
+}
+
+/*
+ * depricated functions that are now just stubs.
+ */
+/*
+ * Close the database
+ */
+void
+__CERT_ClosePermCertDB(CERTCertDBHandle *handle)
+{
+ PORT_Assert("CERT_ClosePermCertDB is Depricated" == NULL);
+ return;
+}
+
+SECStatus
+CERT_OpenCertDBFilename(CERTCertDBHandle *handle, char *certdbname,
+ PRBool readOnly)
+{
+ PORT_Assert("CERT_OpenCertDBFilename is Depricated" == NULL);
+ return SECFailure;
+}
+
+SECItem *
+SECKEY_HashPassword(char *pw, SECItem *salt)
+{
+ PORT_Assert("SECKEY_HashPassword is Depricated" == NULL);
+ return NULL;
+}
+
+SECStatus
+__CERT_TraversePermCertsForSubject(CERTCertDBHandle *handle,
+ SECItem *derSubject,
+ void *cb, void *cbarg)
+{
+ PORT_Assert("CERT_TraversePermCertsForSubject is Depricated" == NULL);
+ return SECFailure;
+}
+
+
+SECStatus
+__CERT_TraversePermCertsForNickname(CERTCertDBHandle *handle, char *nickname,
+ void *cb, void *cbarg)
+{
+ PORT_Assert("CERT_TraversePermCertsForNickname is Depricated" == NULL);
+ return SECFailure;
+}
+
+
+
diff --git a/security/nss/lib/certdb/xauthkid.c b/security/nss/lib/certdb/xauthkid.c
new file mode 100644
index 000000000..089d16f14
--- /dev/null
+++ b/security/nss/lib/certdb/xauthkid.c
@@ -0,0 +1,155 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+ * X.509 v3 Subject Key Usage Extension
+ *
+ */
+
+#include "prtypes.h"
+#include "mcom_db.h"
+#include "seccomon.h"
+#include "secdert.h"
+#include "secoidt.h"
+#include "secasn1t.h"
+#include "secasn1.h"
+#include "secport.h"
+#include "certt.h"
+#include "genname.h"
+#include "secerr.h"
+
+
+const SEC_ASN1Template CERTAuthKeyIDTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTAuthKeyID) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 0,
+ offsetof(CERTAuthKeyID,keyID), SEC_OctetStringTemplate},
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
+ offsetof(CERTAuthKeyID, DERAuthCertIssuer), CERT_GeneralNamesTemplate},
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 2,
+ offsetof(CERTAuthKeyID,authCertSerialNumber), SEC_IntegerTemplate},
+ { 0 }
+};
+
+
+
+SECStatus CERT_EncodeAuthKeyID (PRArenaPool *arena, CERTAuthKeyID *value, SECItem *encodedValue)
+{
+ SECStatus rv = SECFailure;
+
+ PORT_Assert (value);
+ PORT_Assert (arena);
+ PORT_Assert (value->DERAuthCertIssuer == NULL);
+ PORT_Assert (encodedValue);
+
+ do {
+
+ /* If both of the authCertIssuer and the serial number exist, encode
+ the name first. Otherwise, it is an error if one exist and the other
+ is not.
+ */
+ if (value->authCertIssuer) {
+ if (!value->authCertSerialNumber.data) {
+ PORT_SetError (SEC_ERROR_EXTENSION_VALUE_INVALID);
+ break;
+ }
+
+ value->DERAuthCertIssuer = cert_EncodeGeneralNames
+ (arena, value->authCertIssuer);
+ if (!value->DERAuthCertIssuer) {
+ PORT_SetError (SEC_ERROR_EXTENSION_VALUE_INVALID);
+ break;
+ }
+ }
+ else if (value->authCertSerialNumber.data) {
+ PORT_SetError (SEC_ERROR_EXTENSION_VALUE_INVALID);
+ break;
+ }
+
+ if (SEC_ASN1EncodeItem (arena, encodedValue, value,
+ CERTAuthKeyIDTemplate) == NULL)
+ break;
+ rv = SECSuccess;
+
+ } while (0);
+ return(rv);
+}
+
+CERTAuthKeyID *
+CERT_DecodeAuthKeyID (PRArenaPool *arena, SECItem *encodedValue)
+{
+ CERTAuthKeyID * value = NULL;
+ SECStatus rv = SECFailure;
+ void * mark;
+ SECItem newEncodedValue;
+
+ PORT_Assert (arena);
+
+ do {
+ mark = PORT_ArenaMark (arena);
+ value = (CERTAuthKeyID*)PORT_ArenaZAlloc (arena, sizeof (*value));
+ value->DERAuthCertIssuer = NULL;
+ if (value == NULL)
+ break;
+ /* copy the DER into the arena, since Quick DER returns data that points
+ into the DER input, which may get freed by the caller */
+ rv = SECITEM_CopyItem(arena, &newEncodedValue, encodedValue);
+ if ( rv != SECSuccess ) {
+ break;
+ }
+
+ rv = SEC_QuickDERDecodeItem
+ (arena, value, CERTAuthKeyIDTemplate, &newEncodedValue);
+ if (rv != SECSuccess)
+ break;
+
+ value->authCertIssuer = cert_DecodeGeneralNames (arena, value->DERAuthCertIssuer);
+ if (value->authCertIssuer == NULL)
+ break;
+
+ /* what if the general name contains other format but not URI ?
+ hl
+ */
+ if ((value->authCertSerialNumber.data && !value->authCertIssuer) ||
+ (!value->authCertSerialNumber.data && value->authCertIssuer)){
+ PORT_SetError (SEC_ERROR_EXTENSION_VALUE_INVALID);
+ break;
+ }
+ } while (0);
+
+ if (rv != SECSuccess) {
+ PORT_ArenaRelease (arena, mark);
+ return ((CERTAuthKeyID *)NULL);
+ }
+ PORT_ArenaUnmark(arena, mark);
+ return (value);
+}
diff --git a/security/nss/lib/certdb/xbsconst.c b/security/nss/lib/certdb/xbsconst.c
new file mode 100644
index 000000000..fea0e5dc8
--- /dev/null
+++ b/security/nss/lib/certdb/xbsconst.c
@@ -0,0 +1,168 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+ * X.509 v3 Basic Constraints Extension
+ */
+
+#include "prtypes.h"
+#include "mcom_db.h"
+#include "seccomon.h"
+#include "secdert.h"
+#include "secoidt.h"
+#include "secasn1t.h"
+#include "secasn1.h"
+#include "certt.h"
+#include "secder.h"
+#include "prprf.h"
+#include "secerr.h"
+
+typedef struct EncodedContext{
+ SECItem isCA;
+ SECItem pathLenConstraint;
+ SECItem encodedValue;
+ PRArenaPool *arena;
+}EncodedContext;
+
+static const SEC_ASN1Template CERTBasicConstraintsTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(EncodedContext) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, /* XXX DER_DEFAULT */
+ offsetof(EncodedContext,isCA)},
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_INTEGER,
+ offsetof(EncodedContext,pathLenConstraint) },
+ { 0, }
+};
+
+static unsigned char hexTrue = 0xff;
+static unsigned char hexFalse = 0x00;
+
+#define GEN_BREAK(status) rv = status; break;
+
+SECStatus CERT_EncodeBasicConstraintValue
+ (PRArenaPool *arena, CERTBasicConstraints *value, SECItem *encodedValue)
+{
+ EncodedContext encodeContext;
+ PRArenaPool *our_pool = NULL;
+ SECStatus rv = SECSuccess;
+
+ do {
+ PORT_Memset (&encodeContext, 0, sizeof (encodeContext));
+ if (!value->isCA && value->pathLenConstraint >= 0) {
+ PORT_SetError (SEC_ERROR_EXTENSION_VALUE_INVALID);
+ GEN_BREAK (SECFailure);
+ }
+
+ encodeContext.arena = arena;
+ if (value->isCA == PR_TRUE) {
+ encodeContext.isCA.data = &hexTrue ;
+ encodeContext.isCA.len = 1;
+ }
+
+ /* If the pathLenConstraint is less than 0, then it should be
+ * omitted from the encoding.
+ */
+ if (value->isCA && value->pathLenConstraint >= 0) {
+ our_pool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
+ if (our_pool == NULL) {
+ PORT_SetError (SEC_ERROR_NO_MEMORY);
+ GEN_BREAK (SECFailure);
+ }
+ if (SEC_ASN1EncodeUnsignedInteger
+ (our_pool, &encodeContext.pathLenConstraint,
+ (unsigned long)value->pathLenConstraint) == NULL) {
+ PORT_SetError (SEC_ERROR_NO_MEMORY);
+ GEN_BREAK (SECFailure);
+ }
+ }
+ if (SEC_ASN1EncodeItem (arena, encodedValue, &encodeContext,
+ CERTBasicConstraintsTemplate) == NULL) {
+ GEN_BREAK (SECFailure);
+ }
+ } while (0);
+ if (our_pool)
+ PORT_FreeArena (our_pool, PR_FALSE);
+ return(rv);
+
+}
+
+SECStatus CERT_DecodeBasicConstraintValue
+ (CERTBasicConstraints *value, SECItem *encodedValue)
+{
+ EncodedContext decodeContext;
+ PRArenaPool *our_pool;
+ SECStatus rv = SECSuccess;
+
+ do {
+ PORT_Memset (&decodeContext, 0, sizeof (decodeContext));
+ /* initialize the value just in case we got "0x30 00", or when the
+ pathLenConstraint is omitted.
+ */
+ decodeContext.isCA.data =&hexFalse;
+ decodeContext.isCA.len = 1;
+
+ our_pool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
+ if (our_pool == NULL) {
+ PORT_SetError (SEC_ERROR_NO_MEMORY);
+ GEN_BREAK (SECFailure);
+ }
+
+ rv = SEC_QuickDERDecodeItem
+ (our_pool, &decodeContext, CERTBasicConstraintsTemplate, encodedValue);
+ if (rv == SECFailure)
+ break;
+
+ value->isCA = (PRBool)(*decodeContext.isCA.data);
+ if (decodeContext.pathLenConstraint.data == NULL) {
+ /* if the pathLenConstraint is not encoded, and the current setting
+ is CA, then the pathLenConstraint should be set to a negative number
+ for unlimited certificate path.
+ */
+ if (value->isCA)
+ value->pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT;
+ }
+ else if (value->isCA)
+ value->pathLenConstraint = DER_GetUInteger (&decodeContext.pathLenConstraint);
+ else {
+ /* here we get an error where the subject is not a CA, but
+ the pathLenConstraint is set */
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ GEN_BREAK (SECFailure);
+ break;
+ }
+
+ } while (0);
+ PORT_FreeArena (our_pool, PR_FALSE);
+ return (rv);
+
+}
diff --git a/security/nss/lib/certdb/xconst.c b/security/nss/lib/certdb/xconst.c
new file mode 100644
index 000000000..d86483098
--- /dev/null
+++ b/security/nss/lib/certdb/xconst.c
@@ -0,0 +1,257 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+ * X.509 Extension Encoding
+ */
+
+#include "prtypes.h"
+#include "mcom_db.h"
+#include "seccomon.h"
+#include "secdert.h"
+#include "secoidt.h"
+#include "secasn1t.h"
+#include "secasn1.h"
+#include "certt.h"
+#include "secder.h"
+#include "prprf.h"
+#include "xconst.h"
+#include "genname.h"
+#include "secasn1.h"
+#include "secerr.h"
+
+
+static const SEC_ASN1Template CERTSubjectKeyIDTemplate[] = {
+ { SEC_ASN1_OCTET_STRING }
+};
+
+
+static const SEC_ASN1Template CERTIA5TypeTemplate[] = {
+ { SEC_ASN1_IA5_STRING }
+};
+
+
+static const SEC_ASN1Template CERTPrivateKeyUsagePeriodTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(PKUPEncodedContext) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 0,
+ offsetof(PKUPEncodedContext, notBefore), SEC_GeneralizedTimeTemplate},
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 1,
+ offsetof(PKUPEncodedContext, notAfter), SEC_GeneralizedTimeTemplate},
+ { 0, }
+};
+
+
+const SEC_ASN1Template CERTAltNameTemplate[] = {
+ { SEC_ASN1_CONSTRUCTED, offsetof(AltNameEncodedContext, encodedGenName),
+ CERT_GeneralNamesTemplate}
+};
+
+const SEC_ASN1Template CERTAuthInfoAccessItemTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTAuthInfoAccess) },
+ { SEC_ASN1_OBJECT_ID,
+ offsetof(CERTAuthInfoAccess, method) },
+ { SEC_ASN1_ANY,
+ offsetof(CERTAuthInfoAccess, derLocation) },
+ { 0, }
+};
+
+const SEC_ASN1Template CERTAuthInfoAccessTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, CERTAuthInfoAccessItemTemplate }
+};
+
+
+SECStatus
+CERT_EncodeSubjectKeyID(PRArenaPool *arena, char *value, int len, SECItem *encodedValue)
+{
+ SECItem encodeContext;
+ SECStatus rv = SECSuccess;
+
+
+ PORT_Memset (&encodeContext, 0, sizeof (encodeContext));
+
+ if (value != NULL) {
+ encodeContext.data = (unsigned char *)value;
+ encodeContext.len = len;
+ }
+ if (SEC_ASN1EncodeItem (arena, encodedValue, &encodeContext,
+ CERTSubjectKeyIDTemplate) == NULL) {
+ rv = SECFailure;
+ }
+
+ return(rv);
+}
+
+
+SECStatus
+CERT_EncodePublicKeyUsagePeriod(PRArenaPool *arena, PKUPEncodedContext *pkup, SECItem *encodedValue)
+{
+ SECStatus rv = SECSuccess;
+
+ if (SEC_ASN1EncodeItem (arena, encodedValue, pkup,
+ CERTPrivateKeyUsagePeriodTemplate) == NULL) {
+ rv = SECFailure;
+ }
+ return(rv);
+}
+
+
+SECStatus
+CERT_EncodeIA5TypeExtension(PRArenaPool *arena, char *value, SECItem *encodedValue)
+{
+ SECItem encodeContext;
+ SECStatus rv = SECSuccess;
+
+
+ PORT_Memset (&encodeContext, 0, sizeof (encodeContext));
+
+ if (value != NULL) {
+ encodeContext.data = (unsigned char *)value;
+ encodeContext.len = strlen(value);
+ }
+ if (SEC_ASN1EncodeItem (arena, encodedValue, &encodeContext,
+ CERTIA5TypeTemplate) == NULL) {
+ rv = SECFailure;
+ }
+
+ return(rv);
+}
+
+SECStatus
+CERT_EncodeAltNameExtension(PRArenaPool *arena, CERTGeneralName *value, SECItem *encodedValue)
+{
+ SECItem **encodedGenName;
+ SECStatus rv = SECSuccess;
+
+ encodedGenName = cert_EncodeGeneralNames(arena, value);
+ if (SEC_ASN1EncodeItem (arena, encodedValue, &encodedGenName,
+ CERT_GeneralNamesTemplate) == NULL) {
+ rv = SECFailure;
+ }
+
+ return rv;
+}
+
+CERTGeneralName *
+CERT_DecodeAltNameExtension(PRArenaPool *arena, SECItem *EncodedAltName)
+{
+ SECStatus rv = SECSuccess;
+ AltNameEncodedContext encodedContext;
+
+ encodedContext.encodedGenName = NULL;
+ PORT_Memset(&encodedContext, 0, sizeof(AltNameEncodedContext));
+ rv = SEC_ASN1DecodeItem (arena, &encodedContext, CERT_GeneralNamesTemplate,
+ EncodedAltName);
+ if (rv == SECFailure) {
+ goto loser;
+ }
+ if (encodedContext.encodedGenName)
+ return cert_DecodeGeneralNames(arena, encodedContext.encodedGenName);
+ /* Extension contained an empty GeneralNames sequence */
+ /* Treat as extension not found */
+ PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
+loser:
+ return NULL;
+}
+
+
+SECStatus
+CERT_EncodeNameConstraintsExtension(PRArenaPool *arena,
+ CERTNameConstraints *value,
+ SECItem *encodedValue)
+{
+ SECStatus rv = SECSuccess;
+
+ rv = cert_EncodeNameConstraints(value, arena, encodedValue);
+ return rv;
+}
+
+
+CERTNameConstraints *
+CERT_DecodeNameConstraintsExtension(PRArenaPool *arena,
+ SECItem *encodedConstraints)
+{
+ return cert_DecodeNameConstraints(arena, encodedConstraints);
+}
+
+
+CERTAuthInfoAccess **
+cert_DecodeAuthInfoAccessExtension(PRArenaPool *arena,
+ SECItem *encodedExtension)
+{
+ CERTAuthInfoAccess **info = NULL;
+ SECStatus rv;
+ int i;
+
+ rv = SEC_ASN1DecodeItem(arena, &info, CERTAuthInfoAccessTemplate,
+ encodedExtension);
+ if (rv != SECSuccess || info == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; info[i] != NULL; i++) {
+ info[i]->location = CERT_DecodeGeneralName(arena,
+ &(info[i]->derLocation),
+ NULL);
+ }
+ return info;
+}
+
+SECStatus
+cert_EncodeAuthInfoAccessExtension(PRArenaPool *arena,
+ CERTAuthInfoAccess **info,
+ SECItem *dest)
+{
+ SECItem *dummy;
+ int i;
+
+ PORT_Assert(info != NULL);
+ PORT_Assert(dest != NULL);
+ if (info == NULL || dest == NULL) {
+ return SECFailure;
+ }
+
+ for (i = 0; info[i] != NULL; i++) {
+ if (CERT_EncodeGeneralName(info[i]->location, &(info[i]->derLocation),
+ arena) == NULL)
+ /* Note that this may leave some of the locations filled in. */
+ return SECFailure;
+ }
+ dummy = SEC_ASN1EncodeItem(arena, dest, &info,
+ CERTAuthInfoAccessTemplate);
+ if (dummy == NULL) {
+ return SECFailure;
+ }
+ return SECSuccess;
+}
diff --git a/security/nss/lib/certdb/xconst.h b/security/nss/lib/certdb/xconst.h
new file mode 100644
index 000000000..e615fa3b4
--- /dev/null
+++ b/security/nss/lib/certdb/xconst.h
@@ -0,0 +1,82 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+#include "certt.h"
+
+typedef struct PKUPEncodedContext{
+ SECItem notBefore;
+ SECItem notAfter;
+ /* SECItem encodedValue; */
+ PRArenaPool *arena;
+}PKUPEncodedContext;
+
+typedef struct AltNameEncodedContext{
+ SECItem **encodedGenName;
+}AltNameEncodedContext;
+
+
+typedef struct NameConstraint{
+ CERTGeneralName generalName;
+ int min;
+ int max;
+}NameConstraint;
+
+
+
+extern SECStatus
+CERT_EncodePublicKeyUsagePeriod(PRArenaPool *arena, PKUPEncodedContext *pkup,
+ SECItem *encodedValue);
+
+extern SECStatus
+CERT_EncodeNameConstraintsExtension(PRArenaPool *arena, CERTNameConstraints *value,
+ SECItem *encodedValue);
+extern CERTGeneralName *
+CERT_DecodeAltNameExtension(PRArenaPool *arena, SECItem *EncodedAltName);
+
+extern CERTNameConstraints *
+CERT_DecodeNameConstraintsExtension(PRArenaPool *arena, SECItem *encodedConstraints);
+
+extern SECStatus
+CERT_EncodeSubjectKeyID(PRArenaPool *arena, char *value, int len, SECItem *encodedValue);
+
+extern SECStatus
+CERT_EncodeIA5TypeExtension(PRArenaPool *arena, char *value, SECItem *encodedValue);
+
+CERTAuthInfoAccess **
+cert_DecodeAuthInfoAccessExtension(PRArenaPool *arena,
+ SECItem *encodedExtension);
+
+SECStatus
+cert_EncodeAuthInfoAccessExtension(PRArenaPool *arena,
+ CERTAuthInfoAccess **info,
+ SECItem *dest);