summaryrefslogtreecommitdiff
path: root/mozilla/security/nss/lib/certhigh/certhigh.c
diff options
context:
space:
mode:
Diffstat (limited to 'mozilla/security/nss/lib/certhigh/certhigh.c')
-rw-r--r--mozilla/security/nss/lib/certhigh/certhigh.c1225
1 files changed, 1225 insertions, 0 deletions
diff --git a/mozilla/security/nss/lib/certhigh/certhigh.c b/mozilla/security/nss/lib/certhigh/certhigh.c
new file mode 100644
index 0000000..6081364
--- /dev/null
+++ b/mozilla/security/nss/lib/certhigh/certhigh.c
@@ -0,0 +1,1225 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * 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 the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+#include "nspr.h"
+#include "secerr.h"
+#include "secasn1.h"
+#include "seccomon.h"
+#include "pk11func.h"
+#include "certdb.h"
+#include "certt.h"
+#include "cert.h"
+#include "certxutl.h"
+
+#include "nsspki.h"
+#include "pki.h"
+#include "pkit.h"
+#include "pkitm.h"
+#include "pki3hack.h"
+
+
+PRBool
+CERT_MatchNickname(char *name1, char *name2) {
+ char *nickname1= NULL;
+ char *nickname2 = NULL;
+ char *token1;
+ char *token2;
+ char *token = NULL;
+ int len;
+
+ /* first deal with the straight comparison */
+ if (PORT_Strcmp(name1, name2) == 0) {
+ return PR_TRUE;
+ }
+ /* we need to handle the case where one name has an explicit token and the other
+ * doesn't */
+ token1 = PORT_Strchr(name1,':');
+ token2 = PORT_Strchr(name2,':');
+ if ((token1 && token2) || (!token1 && !token2)) {
+ /* either both token names are specified or neither are, not match */
+ return PR_FALSE;
+ }
+ if (token1) {
+ token=name1;
+ nickname1=token1;
+ nickname2=name2;
+ } else {
+ token=name2;
+ nickname1=token2;
+ nickname2=name1;
+ }
+ len = nickname1-token;
+ nickname1++;
+ if (PORT_Strcmp(nickname1,nickname2) != 0) {
+ return PR_FALSE;
+ }
+ /* compare the other token with the internal slot here */
+ return PR_TRUE;
+}
+
+/*
+ * 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)
+{
+ CERTCertNicknames *nicknames = NULL;
+ char **nnptr;
+ int nn;
+ CERTCertificate *cert = NULL;
+ CERTCertList *certList = NULL;
+ SECStatus rv;
+ int64 time;
+ CERTCertListNode *node = NULL;
+ CERTCertListNode *freenode = NULL;
+ int n;
+
+ time = PR_Now();
+
+ nicknames = CERT_GetCertNicknames(handle, SEC_CERT_NICKNAMES_USER,
+ proto_win);
+
+ if ( ( nicknames == NULL ) || ( nicknames->numnicknames == 0 ) ) {
+ goto loser;
+ }
+
+ nnptr = nicknames->nicknames;
+ nn = nicknames->numnicknames;
+
+ while ( nn > 0 ) {
+ cert = NULL;
+ /* use the pk11 call so that we pick up any certs on tokens,
+ * which may require login
+ */
+ if ( proto_win != NULL ) {
+ cert = PK11_FindCertFromNickname(*nnptr,proto_win);
+ }
+
+ /* Sigh, It turns out if the cert is already in the temp db, because
+ * it's in the perm db, then the nickname lookup doesn't work.
+ * since we already have the cert here, though, than we can just call
+ * CERT_CreateSubjectCertList directly. For those cases where we didn't
+ * find the cert in pkcs #11 (because we didn't have a password arg,
+ * or because the nickname is for a peer, server, or CA cert, then we
+ * go look the cert up.
+ */
+ if (cert == NULL) {
+ cert = CERT_FindCertByNickname(handle,*nnptr);
+ }
+
+ if ( cert != NULL ) {
+ /* collect certs for this nickname, sorting them into the list */
+ certList = CERT_CreateSubjectCertList(certList, handle,
+ &cert->derSubject, time, validOnly);
+
+ CERT_FilterCertListForUserCerts(certList);
+
+ /* drop the extra reference */
+ CERT_DestroyCertificate(cert);
+ }
+
+ nnptr++;
+ nn--;
+ }
+
+ /* remove certs with incorrect usage */
+ rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE);
+
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ /* remove any extra certs for each name */
+ if ( oneCertPerName ) {
+ PRBool *flags;
+
+ nn = nicknames->numnicknames;
+ nnptr = nicknames->nicknames;
+
+ flags = (PRBool *)PORT_ZAlloc(sizeof(PRBool) * nn);
+ if ( flags == NULL ) {
+ goto loser;
+ }
+
+ node = CERT_LIST_HEAD(certList);
+
+ /* treverse all certs in the list */
+ while ( !CERT_LIST_END(node, certList) ) {
+
+ /* find matching nickname index */
+ for ( n = 0; n < nn; n++ ) {
+ if ( CERT_MatchNickname(nnptr[n], node->cert->nickname) ) {
+ /* We found a match. If this is the first one, then
+ * set the flag and move on to the next cert. If this
+ * is not the first one then delete it from the list.
+ */
+ if ( flags[n] ) {
+ /* We have already seen a cert with this nickname,
+ * so delete this one.
+ */
+ freenode = node;
+ node = CERT_LIST_NEXT(node);
+ CERT_RemoveCertListNode(freenode);
+ } else {
+ /* keep the first cert for each nickname, but set the
+ * flag so we know to delete any others with the same
+ * nickname.
+ */
+ flags[n] = PR_TRUE;
+ node = CERT_LIST_NEXT(node);
+ }
+ break;
+ }
+ }
+ if ( n == nn ) {
+ /* if we get here it means that we didn't find a matching
+ * nickname, which should not happen.
+ */
+ PORT_Assert(0);
+ node = CERT_LIST_NEXT(node);
+ }
+ }
+ PORT_Free(flags);
+ }
+
+ goto done;
+
+loser:
+ if ( certList != NULL ) {
+ CERT_DestroyCertList(certList);
+ certList = NULL;
+ }
+
+done:
+ if ( nicknames != NULL ) {
+ CERT_FreeNicknames(nicknames);
+ }
+
+ return(certList);
+}
+
+/*
+ * 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,
+ const char *nickname,
+ SECCertUsage usage,
+ PRBool validOnly,
+ void *proto_win)
+{
+ CERTCertificate *cert = NULL;
+ CERTCertList *certList = NULL;
+ SECStatus rv;
+ int64 time;
+
+ time = PR_Now();
+
+ /* use the pk11 call so that we pick up any certs on tokens,
+ * which may require login
+ */
+ /* XXX - why is this restricted? */
+ if ( proto_win != NULL ) {
+ cert = PK11_FindCertFromNickname(nickname,proto_win);
+ }
+
+
+ /* sigh, There are still problems find smart cards from the temp
+ * db. This will get smart cards working again. The real fix
+ * is to make sure we can search the temp db by their token nickname.
+ */
+ if (cert == NULL) {
+ cert = CERT_FindCertByNickname(handle,nickname);
+ }
+
+ if ( cert != NULL ) {
+ unsigned int requiredKeyUsage;
+ unsigned int requiredCertType;
+
+ rv = CERT_KeyUsageAndTypeForCertUsage(usage, PR_FALSE,
+ &requiredKeyUsage, &requiredCertType);
+ if ( rv != SECSuccess ) {
+ /* drop the extra reference */
+ CERT_DestroyCertificate(cert);
+ cert = NULL;
+ goto loser;
+ }
+ /* If we already found the right cert, just return it */
+ if ( (!validOnly || CERT_CheckCertValidTimes(cert, time, PR_FALSE)
+ == secCertTimeValid) &&
+ (CERT_CheckKeyUsage(cert, requiredKeyUsage) == SECSuccess) &&
+ (cert->nsCertType & requiredCertType) &&
+ CERT_IsUserCert(cert) ) {
+ return(cert);
+ }
+
+ /* collect certs for this nickname, sorting them into the list */
+ certList = CERT_CreateSubjectCertList(certList, handle,
+ &cert->derSubject, time, validOnly);
+
+ CERT_FilterCertListForUserCerts(certList);
+
+ /* drop the extra reference */
+ CERT_DestroyCertificate(cert);
+ cert = NULL;
+ }
+
+ if ( certList == NULL ) {
+ goto loser;
+ }
+
+ /* remove certs with incorrect usage */
+ rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE);
+
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ if ( ! CERT_LIST_END(CERT_LIST_HEAD(certList), certList) ) {
+ cert = CERT_DupCertificate(CERT_LIST_HEAD(certList)->cert);
+ }
+
+loser:
+ if ( certList != NULL ) {
+ CERT_DestroyCertList(certList);
+ }
+
+ return(cert);
+}
+
+CERTCertList *
+CERT_MatchUserCert(CERTCertDBHandle *handle,
+ SECCertUsage usage,
+ int nCANames, char **caNames,
+ void *proto_win)
+{
+ CERTCertList *certList = NULL;
+ SECStatus rv;
+
+ certList = CERT_FindUserCertsByUsage(handle, usage, PR_TRUE, PR_TRUE,
+ proto_win);
+ if ( certList == NULL ) {
+ goto loser;
+ }
+
+ rv = CERT_FilterCertListByCANames(certList, nCANames, caNames, usage);
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ goto done;
+
+loser:
+ if ( certList != NULL ) {
+ CERT_DestroyCertList(certList);
+ certList = NULL;
+ }
+
+done:
+
+ return(certList);
+}
+
+
+typedef struct stringNode {
+ struct stringNode *next;
+ char *string;
+} stringNode;
+
+static PRStatus
+CollectNicknames( NSSCertificate *c, void *data)
+{
+ CERTCertNicknames *names;
+ PRBool saveit = PR_FALSE;
+ stringNode *node;
+ int len;
+#ifdef notdef
+ NSSTrustDomain *td;
+ NSSTrust *trust;
+#endif
+ char *stanNickname;
+ char *nickname = NULL;
+
+ names = (CERTCertNicknames *)data;
+
+ stanNickname = nssCertificate_GetNickname(c,NULL);
+
+ if ( stanNickname ) {
+ if (names->what == SEC_CERT_NICKNAMES_USER) {
+ saveit = NSSCertificate_IsPrivateKeyAvailable(c, NULL, NULL);
+ }
+#ifdef notdef
+ else {
+ td = NSSCertificate_GetTrustDomain(c);
+ if (!td) {
+ return PR_SUCCESS;
+ }
+ trust = nssTrustDomain_FindTrustForCertificate(td,c);
+
+ switch(names->what) {
+ case SEC_CERT_NICKNAMES_ALL:
+ if ((trust->sslFlags & (CERTDB_VALID_CA|CERTDB_VALID_PEER) ) ||
+ (trust->emailFlags & (CERTDB_VALID_CA|CERTDB_VALID_PEER) ) ||
+ (trust->objectSigningFlags &
+ (CERTDB_VALID_CA|CERTDB_VALID_PEER))) {
+ saveit = PR_TRUE;
+ }
+
+ break;
+ case SEC_CERT_NICKNAMES_SERVER:
+ if ( trust->sslFlags & CERTDB_VALID_PEER ) {
+ saveit = PR_TRUE;
+ }
+
+ break;
+ case SEC_CERT_NICKNAMES_CA:
+ if (((trust->sslFlags & CERTDB_VALID_CA ) == CERTDB_VALID_CA)||
+ ((trust->emailFlags & CERTDB_VALID_CA ) == CERTDB_VALID_CA) ||
+ ((trust->objectSigningFlags & CERTDB_VALID_CA )
+ == CERTDB_VALID_CA)) {
+ saveit = PR_TRUE;
+ }
+ break;
+ }
+ }
+#endif
+ }
+
+ /* traverse the list of collected nicknames and make sure we don't make
+ * a duplicate
+ */
+ if ( saveit ) {
+ nickname = STAN_GetCERTCertificateName(NULL, c);
+ /* nickname can only be NULL here if we are having memory
+ * alloc problems */
+ if (nickname == NULL) {
+ return PR_FAILURE;
+ }
+ node = (stringNode *)names->head;
+ while ( node != NULL ) {
+ if ( PORT_Strcmp(nickname, node->string) == 0 ) {
+ /* if the string matches, then don't save this one */
+ saveit = PR_FALSE;
+ break;
+ }
+ node = node->next;
+ }
+ }
+
+ if ( saveit ) {
+
+ /* allocate the node */
+ node = (stringNode*)PORT_ArenaAlloc(names->arena, sizeof(stringNode));
+ if ( node == NULL ) {
+ PORT_Free(nickname);
+ return PR_FAILURE;
+ }
+
+ /* copy the string */
+ len = PORT_Strlen(nickname) + 1;
+ node->string = (char*)PORT_ArenaAlloc(names->arena, len);
+ if ( node->string == NULL ) {
+ PORT_Free(nickname);
+ return PR_FAILURE;
+ }
+ PORT_Memcpy(node->string, nickname, len);
+
+ /* link it into the list */
+ node->next = (stringNode *)names->head;
+ names->head = (void *)node;
+
+ /* bump the count */
+ names->numnicknames++;
+ }
+
+ if (nickname) PORT_Free(nickname);
+ return(PR_SUCCESS);
+}
+
+CERTCertNicknames *
+CERT_GetCertNicknames(CERTCertDBHandle *handle, int what, void *wincx)
+{
+ PRArenaPool *arena;
+ CERTCertNicknames *names;
+ int i;
+ stringNode *node;
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if ( arena == NULL ) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return(NULL);
+ }
+
+ names = (CERTCertNicknames *)PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames));
+ if ( names == NULL ) {
+ goto loser;
+ }
+
+ names->arena = arena;
+ names->head = NULL;
+ names->numnicknames = 0;
+ names->nicknames = NULL;
+ names->what = what;
+ names->totallen = 0;
+
+ /* make sure we are logged in */
+ (void) pk11_TraverseAllSlots(NULL, NULL, PR_TRUE, wincx);
+
+ NSSTrustDomain_TraverseCertificates(handle,
+ CollectNicknames, (void *)names);
+ if ( names->numnicknames ) {
+ names->nicknames = (char**)PORT_ArenaAlloc(arena,
+ names->numnicknames * sizeof(char *));
+
+ if ( names->nicknames == NULL ) {
+ goto loser;
+ }
+
+ node = (stringNode *)names->head;
+
+ for ( i = 0; i < names->numnicknames; i++ ) {
+ PORT_Assert(node != NULL);
+
+ names->nicknames[i] = node->string;
+ names->totallen += PORT_Strlen(node->string);
+ node = node->next;
+ }
+
+ PORT_Assert(node == NULL);
+ }
+
+ return(names);
+
+loser:
+ PORT_FreeArena(arena, PR_FALSE);
+ return(NULL);
+}
+
+void
+CERT_FreeNicknames(CERTCertNicknames *nicknames)
+{
+ PORT_FreeArena(nicknames->arena, PR_FALSE);
+
+ return;
+}
+
+/* [ FROM pcertdb.c ] */
+
+typedef struct dnameNode {
+ struct dnameNode *next;
+ SECItem name;
+} dnameNode;
+
+void
+CERT_FreeDistNames(CERTDistNames *names)
+{
+ PORT_FreeArena(names->arena, PR_FALSE);
+
+ return;
+}
+
+static SECStatus
+CollectDistNames( CERTCertificate *cert, SECItem *k, void *data)
+{
+ CERTDistNames *names;
+ PRBool saveit = PR_FALSE;
+ CERTCertTrust *trust;
+ dnameNode *node;
+ int len;
+
+ names = (CERTDistNames *)data;
+
+ if ( cert->trust ) {
+ trust = cert->trust;
+
+ /* only collect names of CAs trusted for issuing SSL clients */
+ if ( trust->sslFlags & CERTDB_TRUSTED_CLIENT_CA ) {
+ saveit = PR_TRUE;
+ }
+ }
+
+ if ( saveit ) {
+ /* allocate the node */
+ node = (dnameNode*)PORT_ArenaAlloc(names->arena, sizeof(dnameNode));
+ if ( node == NULL ) {
+ return(SECFailure);
+ }
+
+ /* copy the name */
+ node->name.len = len = cert->derSubject.len;
+ node->name.type = siBuffer;
+ node->name.data = (unsigned char*)PORT_ArenaAlloc(names->arena, len);
+ if ( node->name.data == NULL ) {
+ return(SECFailure);
+ }
+ PORT_Memcpy(node->name.data, cert->derSubject.data, len);
+
+ /* link it into the list */
+ node->next = (dnameNode *)names->head;
+ names->head = (void *)node;
+
+ /* bump the count */
+ names->nnames++;
+ }
+
+ return(SECSuccess);
+}
+
+/*
+ * Return all of the CAs that are "trusted" for SSL.
+ */
+CERTDistNames *
+CERT_DupDistNames(CERTDistNames *orig)
+{
+ PRArenaPool *arena;
+ CERTDistNames *names;
+ int i;
+ SECStatus rv;
+
+ /* allocate an arena to use */
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return(NULL);
+ }
+
+ /* allocate the header structure */
+ names = (CERTDistNames *)PORT_ArenaAlloc(arena, sizeof(CERTDistNames));
+ if (names == NULL) {
+ goto loser;
+ }
+
+ /* initialize the header struct */
+ names->arena = arena;
+ names->head = NULL;
+ names->nnames = orig->nnames;
+ names->names = NULL;
+
+ /* construct the array from the list */
+ if (orig->nnames) {
+ names->names = (SECItem*)PORT_ArenaNewArray(arena, SECItem,
+ orig->nnames);
+ if (names->names == NULL) {
+ goto loser;
+ }
+ for (i = 0; i < orig->nnames; i++) {
+ rv = SECITEM_CopyItem(arena, &names->names[i], &orig->names[i]);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ }
+ return(names);
+
+loser:
+ PORT_FreeArena(arena, PR_FALSE);
+ return(NULL);
+}
+
+CERTDistNames *
+CERT_GetSSLCACerts(CERTCertDBHandle *handle)
+{
+ PRArenaPool *arena;
+ CERTDistNames *names;
+ int i;
+ SECStatus rv;
+ dnameNode *node;
+
+ /* allocate an arena to use */
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if ( arena == NULL ) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return(NULL);
+ }
+
+ /* allocate the header structure */
+ names = (CERTDistNames *)PORT_ArenaAlloc(arena, sizeof(CERTDistNames));
+ if ( names == NULL ) {
+ goto loser;
+ }
+
+ /* initialize the header struct */
+ names->arena = arena;
+ names->head = NULL;
+ names->nnames = 0;
+ names->names = NULL;
+
+ /* collect the names from the database */
+ rv = PK11_TraverseSlotCerts(CollectDistNames, (void *)names, NULL);
+ if ( rv ) {
+ goto loser;
+ }
+
+ /* construct the array from the list */
+ if ( names->nnames ) {
+ names->names = (SECItem*)PORT_ArenaAlloc(arena, names->nnames * sizeof(SECItem));
+
+ if ( names->names == NULL ) {
+ goto loser;
+ }
+
+ node = (dnameNode *)names->head;
+
+ for ( i = 0; i < names->nnames; i++ ) {
+ PORT_Assert(node != NULL);
+
+ names->names[i] = node->name;
+ node = node->next;
+ }
+
+ PORT_Assert(node == NULL);
+ }
+
+ return(names);
+
+loser:
+ PORT_FreeArena(arena, PR_FALSE);
+ return(NULL);
+}
+
+CERTDistNames *
+CERT_DistNamesFromCertList(CERTCertList *certList)
+{
+ CERTDistNames * dnames = NULL;
+ PRArenaPool * arena;
+ CERTCertListNode *node = NULL;
+ SECItem * names = NULL;
+ int listLen = 0, i = 0;
+
+ if (certList == NULL) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+
+ node = CERT_LIST_HEAD(certList);
+ while ( ! CERT_LIST_END(node, certList) ) {
+ listLen += 1;
+ node = CERT_LIST_NEXT(node);
+ }
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) goto loser;
+ dnames = PORT_ArenaZNew(arena, CERTDistNames);
+ if (dnames == NULL) goto loser;
+
+ dnames->arena = arena;
+ dnames->nnames = listLen;
+ dnames->names = names = PORT_ArenaZNewArray(arena, SECItem, listLen);
+ if (names == NULL) goto loser;
+
+ node = CERT_LIST_HEAD(certList);
+ while ( ! CERT_LIST_END(node, certList) ) {
+ CERTCertificate *cert = node->cert;
+ SECStatus rv = SECITEM_CopyItem(arena, &names[i++], &cert->derSubject);
+ if (rv == SECFailure) {
+ goto loser;
+ }
+ node = CERT_LIST_NEXT(node);
+ }
+ return dnames;
+loser:
+ if (arena) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+ return NULL;
+}
+
+CERTDistNames *
+CERT_DistNamesFromNicknames(CERTCertDBHandle *handle, char **nicknames,
+ int nnames)
+{
+ CERTDistNames *dnames = NULL;
+ PRArenaPool *arena;
+ int i, rv;
+ SECItem *names = NULL;
+ CERTCertificate *cert = NULL;
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) goto loser;
+ dnames = PORT_ArenaZNew(arena, CERTDistNames);
+ if (dnames == NULL) goto loser;
+
+ dnames->arena = arena;
+ dnames->nnames = nnames;
+ dnames->names = names = PORT_ArenaZNewArray(arena, SECItem, nnames);
+ if (names == NULL) goto loser;
+
+ for (i = 0; i < nnames; i++) {
+ cert = CERT_FindCertByNicknameOrEmailAddr(handle, nicknames[i]);
+ if (cert == NULL) goto loser;
+ rv = SECITEM_CopyItem(arena, &names[i], &cert->derSubject);
+ if (rv == SECFailure) goto loser;
+ CERT_DestroyCertificate(cert);
+ }
+ return dnames;
+
+loser:
+ if (cert != NULL)
+ CERT_DestroyCertificate(cert);
+ if (arena != NULL)
+ PORT_FreeArena(arena, PR_FALSE);
+ return NULL;
+}
+
+/* [ from pcertdb.c - calls Ascii to Name ] */
+/*
+ * Lookup a certificate in the database by name
+ */
+CERTCertificate *
+CERT_FindCertByNameString(CERTCertDBHandle *handle, char *nameStr)
+{
+ CERTName *name;
+ SECItem *nameItem;
+ CERTCertificate *cert = NULL;
+ PRArenaPool *arena = NULL;
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+
+ if ( arena == NULL ) {
+ goto loser;
+ }
+
+ name = CERT_AsciiToName(nameStr);
+
+ if ( name ) {
+ nameItem = SEC_ASN1EncodeItem (arena, NULL, (void *)name,
+ CERT_NameTemplate);
+ if ( nameItem != NULL ) {
+ cert = CERT_FindCertByName(handle, nameItem);
+ }
+ CERT_DestroyName(name);
+ }
+
+loser:
+ if ( arena ) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ return(cert);
+}
+
+/* From certv3.c */
+
+CERTCrlDistributionPoints *
+CERT_FindCRLDistributionPoints (CERTCertificate *cert)
+{
+ SECItem encodedExtenValue;
+ SECStatus rv;
+ CERTCrlDistributionPoints *dps;
+
+ encodedExtenValue.data = NULL;
+ encodedExtenValue.len = 0;
+
+ rv = cert_FindExtension(cert->extensions, SEC_OID_X509_CRL_DIST_POINTS,
+ &encodedExtenValue);
+ if ( rv != SECSuccess ) {
+ return (NULL);
+ }
+
+ dps = CERT_DecodeCRLDistributionPoints(cert->arena, &encodedExtenValue);
+
+ PORT_Free(encodedExtenValue.data);
+
+ return dps;
+}
+
+/* From crl.c */
+CERTSignedCrl * CERT_ImportCRL
+ (CERTCertDBHandle *handle, SECItem *derCRL, char *url, int type, void *wincx)
+{
+ CERTSignedCrl* retCrl = NULL;
+ PK11SlotInfo* slot = PK11_GetInternalKeySlot();
+ retCrl = PK11_ImportCRL(slot, derCRL, url, type, wincx,
+ CRL_IMPORT_DEFAULT_OPTIONS, NULL, CRL_DECODE_DEFAULT_OPTIONS);
+ PK11_FreeSlot(slot);
+
+ return retCrl;
+}
+
+/* From certdb.c */
+static SECStatus
+cert_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage, PRBool trusted)
+{
+ SECStatus rv;
+ SECItem *derCert;
+ CERTCertificate *cert = NULL;
+ CERTCertificate *newcert = NULL;
+ CERTCertDBHandle *handle;
+ CERTCertTrust trust;
+ PRBool isca;
+ char *nickname;
+ unsigned int certtype;
+
+ handle = CERT_GetDefaultCertDB();
+
+ while (numcerts--) {
+ derCert = certs;
+ certs++;
+
+ /* decode my certificate */
+ /* This use is ok -- only looks at decoded parts, calls NewTemp later */
+ newcert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
+ if ( newcert == NULL ) {
+ goto loser;
+ }
+
+ if (!trusted) {
+ /* make sure that cert is valid */
+ rv = CERT_CertTimesValid(newcert);
+ if ( rv == SECFailure ) {
+ goto endloop;
+ }
+ }
+
+ /* does it have the CA extension */
+
+ /*
+ * Make sure that if this is an intermediate CA in the chain that
+ * it was given permission by its signer to be a CA.
+ */
+ isca = CERT_IsCACert(newcert, &certtype);
+
+ if ( !isca ) {
+ if (!trusted) {
+ goto endloop;
+ }
+ trust.sslFlags = CERTDB_VALID_CA;
+ trust.emailFlags = CERTDB_VALID_CA;
+ trust.objectSigningFlags = CERTDB_VALID_CA;
+ } else {
+ /* SSL ca's must have the ssl bit set */
+ if ( ( certUsage == certUsageSSLCA ) &&
+ (( certtype & NS_CERT_TYPE_SSL_CA ) != NS_CERT_TYPE_SSL_CA )) {
+ goto endloop;
+ }
+
+ /* it passed all of the tests, so lets add it to the database */
+ /* mark it as a CA */
+ PORT_Memset((void *)&trust, 0, sizeof(trust));
+ switch ( certUsage ) {
+ case certUsageSSLCA:
+ trust.sslFlags = CERTDB_VALID_CA;
+ break;
+ case certUsageUserCertImport:
+ if ((certtype & NS_CERT_TYPE_SSL_CA) == NS_CERT_TYPE_SSL_CA) {
+ trust.sslFlags = CERTDB_VALID_CA;
+ }
+ if ((certtype & NS_CERT_TYPE_EMAIL_CA)
+ == NS_CERT_TYPE_EMAIL_CA ) {
+ trust.emailFlags = CERTDB_VALID_CA;
+ }
+ if ( ( certtype & NS_CERT_TYPE_OBJECT_SIGNING_CA ) ==
+ NS_CERT_TYPE_OBJECT_SIGNING_CA ) {
+ trust.objectSigningFlags = CERTDB_VALID_CA;
+ }
+ break;
+ default:
+ PORT_Assert(0);
+ break;
+ }
+ }
+
+ cert = CERT_NewTempCertificate(handle, derCert, NULL,
+ PR_FALSE, PR_FALSE);
+ if ( cert == NULL ) {
+ goto loser;
+ }
+
+ /* if the cert is temp, make it perm; otherwise we're done */
+ if (cert->istemp) {
+ /* get a default nickname for it */
+ nickname = CERT_MakeCANickname(cert);
+
+ rv = CERT_AddTempCertToPerm(cert, nickname, &trust);
+
+ /* free the nickname */
+ if ( nickname ) {
+ PORT_Free(nickname);
+ }
+ } else {
+ rv = SECSuccess;
+ }
+
+ CERT_DestroyCertificate(cert);
+ cert = NULL;
+
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+endloop:
+ if ( newcert ) {
+ CERT_DestroyCertificate(newcert);
+ newcert = NULL;
+ }
+
+ }
+
+ rv = SECSuccess;
+ goto done;
+loser:
+ rv = SECFailure;
+done:
+
+ if ( newcert ) {
+ CERT_DestroyCertificate(newcert);
+ newcert = NULL;
+ }
+
+ if ( cert ) {
+ CERT_DestroyCertificate(cert);
+ cert = NULL;
+ }
+
+ return(rv);
+}
+
+SECStatus
+CERT_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage)
+{
+ return cert_ImportCAChain(certs, numcerts, certUsage, PR_FALSE);
+}
+
+SECStatus
+CERT_ImportCAChainTrusted(SECItem *certs, int numcerts, SECCertUsage certUsage) {
+ return cert_ImportCAChain(certs, numcerts, certUsage, PR_TRUE);
+}
+
+/* Moved from certdb.c */
+/*
+** CERT_CertChainFromCert
+**
+** Construct a CERTCertificateList consisting of the given certificate and all
+** of the issuer certs until we either get to a self-signed cert or can't find
+** an issuer. Since we don't know how many certs are in the chain we have to
+** build a linked list first as we count them.
+*/
+
+typedef struct certNode {
+ struct certNode *next;
+ CERTCertificate *cert;
+} certNode;
+
+CERTCertificateList *
+CERT_CertChainFromCert(CERTCertificate *cert, SECCertUsage usage,
+ PRBool includeRoot)
+{
+ CERTCertificateList *chain = NULL;
+ NSSCertificate **stanChain;
+ NSSCertificate *stanCert;
+ PRArenaPool *arena;
+ NSSUsage nssUsage;
+ int i, len;
+ NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
+ NSSCryptoContext *cc = STAN_GetDefaultCryptoContext();
+
+ stanCert = STAN_GetNSSCertificate(cert);
+ if (!stanCert) {
+ /* error code is set */
+ return NULL;
+ }
+ nssUsage.anyUsage = PR_FALSE;
+ nssUsage.nss3usage = usage;
+ nssUsage.nss3lookingForCA = PR_FALSE;
+ stanChain = NSSCertificate_BuildChain(stanCert, NULL, &nssUsage, NULL, NULL,
+ CERT_MAX_CERT_CHAIN, NULL, NULL, td, cc);
+ if (!stanChain) {
+ PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
+ return NULL;
+ }
+
+ len = 0;
+ stanCert = stanChain[0];
+ while (stanCert) {
+ stanCert = stanChain[++len];
+ }
+
+ arena = PORT_NewArena(4096);
+ if (arena == NULL) {
+ goto loser;
+ }
+
+ chain = (CERTCertificateList *)PORT_ArenaAlloc(arena,
+ sizeof(CERTCertificateList));
+ if (!chain) goto loser;
+ chain->certs = (SECItem*)PORT_ArenaAlloc(arena, len * sizeof(SECItem));
+ if (!chain->certs) goto loser;
+ i = 0;
+ stanCert = stanChain[i];
+ while (stanCert) {
+ SECItem derCert;
+ CERTCertificate *cCert = STAN_GetCERTCertificate(stanCert);
+ if (!cCert) {
+ goto loser;
+ }
+ derCert.len = (unsigned int)stanCert->encoding.size;
+ derCert.data = (unsigned char *)stanCert->encoding.data;
+ derCert.type = siBuffer;
+ SECITEM_CopyItem(arena, &chain->certs[i], &derCert);
+ stanCert = stanChain[++i];
+ if (!stanCert && !cCert->isRoot) {
+ /* reached the end of the chain, but the final cert is
+ * not a root. Don't discard it.
+ */
+ includeRoot = PR_TRUE;
+ }
+ CERT_DestroyCertificate(cCert);
+ }
+ if ( !includeRoot && len > 1) {
+ chain->len = len - 1;
+ } else {
+ chain->len = len;
+ }
+
+ chain->arena = arena;
+ nss_ZFreeIf(stanChain);
+ return chain;
+loser:
+ i = 0;
+ stanCert = stanChain[i];
+ while (stanCert) {
+ CERTCertificate *cCert = STAN_GetCERTCertificate(stanCert);
+ if (cCert) {
+ CERT_DestroyCertificate(cCert);
+ }
+ stanCert = stanChain[++i];
+ }
+ nss_ZFreeIf(stanChain);
+ if (arena) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+ return NULL;
+}
+
+/* Builds a CERTCertificateList holding just one DER-encoded cert, namely
+** the one for the cert passed as an argument.
+*/
+CERTCertificateList *
+CERT_CertListFromCert(CERTCertificate *cert)
+{
+ CERTCertificateList *chain = NULL;
+ int rv;
+ PRArenaPool *arena;
+
+ /* arena for SecCertificateList */
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) goto no_memory;
+
+ /* build the CERTCertificateList */
+ chain = (CERTCertificateList *)PORT_ArenaAlloc(arena, sizeof(CERTCertificateList));
+ if (chain == NULL) goto no_memory;
+ chain->certs = (SECItem*)PORT_ArenaAlloc(arena, 1 * sizeof(SECItem));
+ if (chain->certs == NULL) goto no_memory;
+ rv = SECITEM_CopyItem(arena, chain->certs, &(cert->derCert));
+ if (rv < 0) goto loser;
+ chain->len = 1;
+ chain->arena = arena;
+
+ return chain;
+
+no_memory:
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+loser:
+ if (arena != NULL) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+ return NULL;
+}
+
+CERTCertificateList *
+CERT_DupCertList(const CERTCertificateList * oldList)
+{
+ CERTCertificateList *newList = NULL;
+ PRArenaPool *arena = NULL;
+ SECItem *newItem;
+ SECItem *oldItem;
+ int len = oldList->len;
+ int rv;
+
+ /* arena for SecCertificateList */
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL)
+ goto no_memory;
+
+ /* now build the CERTCertificateList */
+ newList = PORT_ArenaNew(arena, CERTCertificateList);
+ if (newList == NULL)
+ goto no_memory;
+ newList->arena = arena;
+ newItem = (SECItem*)PORT_ArenaAlloc(arena, len * sizeof(SECItem));
+ if (newItem == NULL)
+ goto no_memory;
+ newList->certs = newItem;
+ newList->len = len;
+
+ for (oldItem = oldList->certs; len > 0; --len, ++newItem, ++oldItem) {
+ rv = SECITEM_CopyItem(arena, newItem, oldItem);
+ if (rv < 0)
+ goto loser;
+ }
+ return newList;
+
+no_memory:
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+loser:
+ if (arena != NULL) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+ return NULL;
+}
+
+void
+CERT_DestroyCertificateList(CERTCertificateList *list)
+{
+ PORT_FreeArena(list->arena, PR_FALSE);
+}
+